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>
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).
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>
I've fairly recently started learning XSLT after getting to grips with XML and XPath; I'm trying to complete a practice exercise; I think I'm nearly there but I've ran into a problem. So I have the following XML document:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<a>
<b></b>
<b></b>
<b></b>
<b></b>
</a>
</root>
And I'd like to surround the elements with a pair of parent elements (to output the following):
<?xml version="1.0" encoding="UTF-8"?>
<root>
<a>
<b-group>
<b></b>
<b></b>
<b></b>
<b></b>
<b-group>
</a>
Here is my XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:template match="root">
<xsl:element name="root">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="a">
<xsl:element name="a">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="b">
<xsl:element name="b-group">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="b">
<xsl:element name="b">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Despite making several other attempts, I'm having difficulty creating the pair of elements that surround the elements; could anyone point me in the right direction of how to do this please?
You need to do this in the template matching a, for example:
<xsl:template match="a">
<a>
<b-group>
<xsl:apply-templates select="b"/>
</b-group>
</a>
</xsl:template>
Additional notes:
Use a literal result element to create an element whose name is known, instead of xsl:element.
Most of your templates do the same thing: create an element with the same name as the one being matched, and apply templates to its children. Thus they could be consolidated into one. A template like this is known as the identity transform template and it is commonly used when most of the document needs to preserved as is, with only a few modifications. This would reduce your entire stylesheet to just:
<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="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="a">
<a>
<b-group>
<xsl:apply-templates select="b"/>
</b-group>
</a>
</xsl:template>
</xsl:stylesheet>
I have an XML:
<?xml version="1.0" encoding="UTF-8"?>
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/" xmlns:p1="http://www.w3.org/2001/XMLSchema-instance">
<Body>
<reinstateAccountRequest xmlns="http://abc.xyx/">
<serviceRequestContext>
<a>t</a>
<b>t</b>
</serviceRequestContext>
<reinstateAccountInput>
<a>t</a>
<b>t</b>
</reinstateAccountInput>
</reinstateAccountRequest>
</Body>
</Envelope>
I want to add empty xmlns to serviceRequestContext and reinstateAccountInput node
Result XML should look like below:
<?xml version="1.0" encoding="UTF-8"?>
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/" xmlns:p1="http://www.w3.org/2001/XMLSchema-instance">
<Body>
<reinstateAccountRequest xmlns="http://abc.xyx/">
<serviceRequestContext xmlns="">
<a>t</a>
<b>t</b>
</serviceRequestContext>
<reinstateAccountInput xmlns="">
<a>t</a>
<b>t</b>
</reinstateAccountInput>
</reinstateAccountRequest>
</Body>
</Envelope>
How to write an XSLT for this
You can start off by building upon the XSLT identity template, to copy across any existing nodes
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
With this in place, you only then have to write templates where you want to make changes to the nodes. In your case, you want to change the child elements of the reinstateAccountRequest element, and the change you need to make is to create new elements with the same name, but no namespace.
<xsl:template match="abc:reinstateAccountRequest//*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
Where "abc" is a namespace prefix that would be defined to have the same namespace URI as in your input XML.
Here is the full XSLT
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:abc="http://abc.xyx/">
<xsl:output omit-xml-declaration="yes" indent="yes" />
<xsl:template match="abc:reinstateAccountRequest//*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
</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>