There's a lot of references in the internet that has the same problem with me. It is the adding of namespace, I have the same as this one that I saw: Adding namespace in inner parent group in xslt v2.0. But in my case, I don't have a namespace in the parent tag and insert the namespace in the inner level group. I tried to copied the solutions but I can't get the expected output. For example, I have this sample file,
INPUT:
<Record>
<Data>
<Section>
<ID>111222</ID>
</Section>
</Data>
</Record>
EXPECTED:
<Record>
<Data>
<Section xmlns="www.hdgd.co">
<ID>111222</ID>
</Section>
</Data>
</Record>
XSLT:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="Section">
<Section xmlns="www.hdgd.co">
<xsl:copy-of select="*"/>
</Section>
</xsl:template>
The generated output populated an empty namespace in the ID element. And, I need to remove that empty xmlns. Look like this:
<Record>
<Data>
<Section xmlns="www.hdgd.co">
<ID xmlns="">111222</ID>
</Section>
</Data>
</Record>
You cannot use:
<xsl:copy-of select="*"/>
because that copies the child nodes in their original namespace - which is no-namespace. To get the result you want, you must move not only Section to the new namespace, but also all its descendants (and leave all other nodes as they are) - for example:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[ancestor-or-self::Section]">
<xsl:element name="{name()}" namespace="www.hdgd.co">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Related
I have this requirement that I only need to populate the <Group> tag under the <Section>, if the <Group> tag under the <Data> is not present. I can't get the correct output that I want. For example:
INPUT
<Record>
<Data>
<ID>1234DFD57</ID>
<Group>
<abc-KD>243fds</abc-KD>
</Group>
<Section>
<ID>33-2311</ID>
<Group>
<abc-KD>NORM</abc-KD>
</Group>
<Date>2017-03-25</Date>
</Section>
<Date>2017-03-25</Date>
</Data>
</Record>
EXPECTED OUTPUT
<Record>
<Data>
<ID>1234DFD57</ID>
<Group>
<abc-KD>243fds</abc-KD>
</Group>
<Section>
<ID>33-2311</ID>
<Date>2017-03-25</Date>
</Section>
<Date>2017-03-25</Date>
</Data>
</Record>
XSLT:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Section">
<xsl:copy>
<xsl:copy-of select="ID"/>
<xsl:if test="normalize-space(string(../Group)) = ''">
<xsl:copy-of select="Group"/>
</xsl:if>
<xsl:copy-of select="Date"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Your feedback is highly appreciated.
Regards,
Your current stylesheet does the work. More efficient way would be:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<!-- identity transform template -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<!-- do nothing for the Group -->
<xsl:template match="Section[normalize-space(parent::Data/Group) != '']/Group"/>
</xsl:stylesheet>
The identity transform template is the one that copies every node in the xml, while recursively processing them in document order, as it is.
The second template matches the Group elements with the desired condition and does nothing for it, hence omitting them in the output.
The x-path in the #match does the trick:
Section[normalize-space(parent::Data/Group) != '']/Group
It matches those Section/Group elements under Data whose Group doesn't exist or has null value(excluding space characters).
I tried all the codes I've seen in the internet with relevant requirement as I have. However, in my case, I also need to populate the namespace within the inner parent group. My XSLT didn't work as expected. Can anyone help me with this? Thank you.
XSLT CODE:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Section">
<Section xmlns="www.hdgd.co">
<xsl:apply-templates select="#*|node()"/>
</Section>
</xsl:template>
INPUT:
<Record xmlns="www.hdgd.co">
<Data>
<Section>
<ID>1234DFD57</ID>
</Section>
</Data>
EXPECTED OUTPUT:
<Record>
<Data>
<Section xmlns="www.hdgd.co">
<ID>1234DFD57</ID>
</Section>
</Data>
GENERATED OUTPUT:
<Record xmlns="www.hdgd.co">
<Data>
<Section>
<ID>1234DFD57</ID>
</Section>
</Data>
You seem to be unaware of namespaces inheritance. The default namespace declaration at the Record root element is applied to all elements of the input document. Therefore, in order to achieve the requested result, you must take all elements out of their namespace, while leaving the Section element and its descendants unprocessed:
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xpath-default-namespace="www.hdgd.co">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="Section">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
Added:
If your input has attributes that need copying, then change the first template to:
<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:copy-of select="#*"/>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
That sounds as if you want to remove the namespace from Record and Data:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
xpath-default-namespace="www.hdgd.co">
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Record | Data">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="#* | node()"/>
</xsl:element>
</xsl:template>
</xsl:transform>
http://xsltransform.net/bEzjRJM gives
<?xml version="1.0" encoding="UTF-8"?><Record>
<Data>
<Section xmlns="www.hdgd.co">
<ID>1234DFD57</ID>
</Section>
</Data>
</Record>
I want to compare the attributes of two xml-Files and identity transform the input file in the same step. The output xml should only contain elements whose attributes occur in the comparing xml. As shown in the given example, the last concept node should not be outputted, as there is no matching attribute in the comparing.xml
input.xml
<navigation
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<facets>
<facet id="d1e12000000000000000000000011111">
<title xml:lang="en">sometxt</title>
<title xml:lang="de">eintxt</title>
<concepts>
<concept id="d1e12000000000000000000000000000">
<title xml:lang="en">sometxt</title>
<title xml:lang="de">eintxt</title>
<concepts>
<concept id="d1e19000000000000000000000000000">
<title xml:lang="en">sometxt</title>
<title xml:lang="de">eintxt</title>
<concepts>
</concepts>
</concept>
</concepts>
</concept>
</concepts>
</facet>
</facets>
part of comparing.xml with indefinite heading-levels
<foo>
<heading class="d1e12000000000000000000000011111|d1e12000000000000000000000000000">Myheading</heading>
<chapter>
<heading class="d1e12000000000000000000000011111|d1e12000000000000000000000000000">myheading</heading>
<operation>
<heading class="d1e12000000000000000000000011111|d1e12000000000000000000000000000">another heading</heading>
</operation>
</chapter>
desired output.xml with only applicable id's
<nav:navigation
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:nav="http://www.nav.de/">
<nav:facets>
<nav:facet id="d1e12000000000000000000000011111">
<nav:title xml:lang="en">sometxt</nav:title>
<nav:title xml:lang="de">eintxt</nav:title>
<nav:concepts>
<nav:concept id="d1e12000000000000000000000000000">
<nav:title xml:lang="en">sometxt</nav:title>
<nav:title xml:lang="de">eintxt</nav:title>
<nav:concepts>
</nav:concepts>
</nav:concept>
</nav:concepts>
</nav:facet>
</nav:facets>
my xsl so far
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:nav="http://www.nav.de/"
version="2.0" >
<xsl:output method="xml" indent="yes" encoding="utf-8"/>
<xsl:variable name="docu" select="document(comparing.xml)"/>
<xsl:template match="*">
<xsl:element name="nav:{name()}" namespace="http://www.nav.de/">
<xsl:copy-of select="namespace::*"/>
<xsl:apply-templates select="node()|#*"/>
</xsl:element>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
EDIT: sorry for posting this in the comment-section. I've tried something along those lines, but it didn't work
<xsl:template match="concept | facet">
<xsl:variable name="foo-id" select="#id"/>
<xsl:for-each select="$docu//heading">
<xsl:if test="contains(./#class, $foo-id)">
<xsl:apply-templates/>
</xsl:if>
</xsl:for-each>
</xsl:template>
I would suggest you try it this way:
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:nav="http://www.nav.de/">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="comparing-url" select="'comparing.xml'"/>
<xsl:key name="comp" match="#class" use="tokenize(., '\|')" />
<xsl:template match="*">
<xsl:element name="nav:{name()}" >
<xsl:copy-of select="#*"/>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="*[#id][not(key('comp', #id, document($comparing-url)))]"/>
</xsl:stylesheet>
I am trying to remove all empty elements after I have finished the transformation however I am just not coming right.
I have the following XML
<root>
<record name='1'>
<Child1>value1</Child1>
<Child2>value2</Child2>
</record>
<record name='2'>
<Child1>value1</Child1>
<Child2>value2</Child2>
</record>
<record name='3'>
<Child1>value1</Child1>
<Child2>value2</Child2>
</record>
</root>
and I want the output to be
<root>
<record name="1">
<Element>1</Element>
</record>
</root>
however I keep getting all the empty record elements as well and I can't figure out how to get rid of them.
<root>
<record>
<Element>1</Element>
</record>
<record/>
<record/>
</root>
This is my stylesheet
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//record">
<xsl:copy>
<xsl:call-template name="SimpleNode"/>
</xsl:copy>
</xsl:template>
<xsl:template name="SimpleNode">
<xsl:if test="#name = '1'">
<Element><xsl:value-of select="#name"/></Element>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
I would rewrite your XSLT a little to match record elements differently depending on the value of their #name attribute.
The following XSLT stylesheet:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<!-- Only produce output for record elements where the name attribute is 1. -->
<xsl:template match="record[#name='1']">
<xsl:copy>
<element>
<xsl:value-of select="#name"/>
</element>
</xsl:copy>
</xsl:template>
<!-- For every other record attribute, output nothing. -->
<xsl:template match="record"/>
</xsl:stylesheet>
produces the following output when applied to your example input XML:
<root>
<record>
<element>1</element>
</record>
</root>
How do I encapsulate nodes around my XML blocks using XSLT?
For example, I have the following XML file.
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" omit-xml-declaration="yes" />
<xsl:template match="/">
<Root>
<VOBaseCollection>
<xsl:apply-templates select="Root/Location" />
</VOBaseCollection>
</Root>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
My input XML file looks like this.
<Root>
<Location><Name>Pennsylvania</Name><Type>State</Type></Location>
</Root>
I wish the output to look like this.
<Root><Container>
<Location><Name>Pennsylvania</Name><Type>State</Type></Location>
</Container>
</Root>
I wish to make sure that a node called <CONTAINER> gets applied every time, it copies over information from Root/Location. What changes do I need to do to my XSLT file?
Summarizing all the answers in comments, this:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="#*|node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Location">
<Container>
<xsl:call-template name="identity"/>
</Container>
</xsl:template>
</xsl:stylesheet>
Result:
<Root>
<Container>
<Location>
<Name>Pennsylvania</Name>
<Type>State</Type>
</Location>
</Container>
</Root>
I am just guessing, and in guess mode it seems that you want this:
EDIT: helped by another guess by Mads Hansen...
Add this to the identity template you already have:
<xsl:template match="Location">
<CONTAINER><xsl:apply-templates/></CONTAINER>
</xsl:template>