I'm new to XSLT and I'm trying to achieve a reasonably simple restructure. I have an xml document representing a person (for illustrative purposes). I have numerous elements under person. From these I want to extract the first_name and last_name (and crucially others) into a new full_name element. I've seen the question here. The "renameWrapped" approach works. However it's not generic enough as I can't guarantee the ordering of the elements in the input document.
I have the following XML:
<?xml version="1.0" encoding="utf-8"?>
<myname:Person xmlns:myname="http://www.myname.co.uk/def">
<myname:attr1>some value</myname:attr1>
<myname:first_name>john</myname:first_name>
<myname:last_name>smith</myname:last_name>
<myname:attr2>some value</myname:attr2>
<!-- other person stuff -->
</myname:Person>
This is transformed by the following xsl:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:myname="http://www.myname.co.uk/def">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@*|node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="myname:Person">
<myname:Person>
<xsl:copy>
<xsl:apply-templates select="@*|node()[local-name() != 'first_name' and local-name() != 'Person' and local-name() != 'last_name']"/>
</xsl:copy>
<myname:FullName>
<xsl:apply-templates select="myname:first_name | myname:last_name"/>
</myname:FullName>
</myname:Person>
</xsl:template>
</xsl:stylesheet>
However this is giving me the following output with myname:Person being duplicated:
<?xml version="1.0" encoding="UTF-8"?>
<myname:Person xmlns:myname="http://www.myname.co.uk/def">
<myname:Person>
<myname:attr1>some value</myname:attr1>
<myname:attr2>some value</myname:attr2>
</myname:Person>
<myname:FullName>
<myname:first_name>john</myname:first_name>
<myname:last_name>smith</myname:last_name>
</myname:FullName>
</myname:Person>
What am I doing wrong?
Thanks in advance for your help.
One of the <myname:Person> elements comes from the literal result element in your template, the other comes from the <xsl:copy>. If you want
<?xml version="1.0" encoding="UTF-8"?>
<myname:Person xmlns:myname="http://www.myname.co.uk/def">
<myname:attr1>some value</myname:attr1>
<myname:attr2>some value</myname:attr2>
<myname:FullName>
<myname:first_name>john</myname:first_name>
<myname:last_name>smith</myname:last_name>
</myname:FullName>
</myname:Person>
then simply leave out the <xsl:copy>, i.e.
<xsl:template match="myname:Person">
<myname:Person>
<xsl:apply-templates select="@*|node()[local-name() != 'first_name' and local-name() != 'Person' and local-name() != 'last_name']"/>
<myname:FullName>
<xsl:apply-templates select="myname:first_name | myname:last_name"/>
</myname:FullName>
</myname:Person>
</xsl:template>
or alternatively leave out the explicit <myname:Person>:
<xsl:template match="myname:Person">
<xsl:copy>
<xsl:apply-templates select="@*|node()[local-name() != 'first_name' and local-name() != 'Person' and local-name() != 'last_name']"/>
<myname:FullName>
<xsl:apply-templates select="myname:first_name | myname:last_name"/>
</myname:FullName>
</xsl:copy>
</xsl:template>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With