Reputation: 13
I have the following example XML file which contains 1,000's of tags.
<AAA>
<BBB>
<CCC>
<DDD>
<EEE>
<1>abc</1>
<2>abc</2>
<3>abc</3>
<4>abc</4>
</EEE>
</DDD>
</CCC>
</BBB>
</AAA>
I need to transform it to the following (add tag 5 with two sub tags and update tag 1).
<AAA>
<BBB>
<CCC>
<DDD>
<EEE>
<1>kkkkkkkk</1>
<2>abc</2>
<3>abc</3>
<4>abc</4>
<5>
<a>abc</a>
<b>abc</b>
</5>
</EEE>
</DDD>
</CCC>
</BBB>
</AAA>
I cannot do both things together at all i.e. I can either update tag 1 or add tag 5. I need to be able to do both. I am using the following xsl transform to add tag 5.
<xsl:template match="@* | node()" name="identity-copy">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="e:AAA/e:BBB/e:CCC/e:DDD/e:EEE">
<xsl:copy>
<xsl:copy-of select="*"/>
<5>
<a>abc</a>
<b>abc</b>
</5>
</xsl:copy>
</xsl:template>
No matter what I try I cannot update tag 1 - the copy-of select="*" seems to be overriding it. Any ideas on how to achieve both the update and addition much appreciated.
Upvotes: 0
Views: 534
Reputation: 338128
Easy, - just exclude <1>
from your copy (XML names can't legally start with a digit, though, so I called it <tag1>
and <tag5>
):
<xsl:template match="e:AAA/e:BBB/e:CCC/e:DDD/e:EEE">
<xsl:copy>
<tag1>kkkkkkkkkk</tag1>
<xsl:copy-of select="*[not(self::tag1)]"/>
<tag5>
<a>abc</a>
<b>abc</b>
</tag5>
</xsl:copy>
</xsl:template>
The above only really works well when you want to replace the very first element and append a new one at the end, in all other cases it messes up the element order.
Assuming you want to replace <tag2>
, using template matching with <xsl:apply-templates>
is better, because it keeps input element order:
<xsl:template match="e:AAA/e:BBB/e:CCC/e:DDD/e:EEE">
<xsl:copy>
<xsl:apply-templates select="*" />
<tag5>
<a>abc</a>
<b>abc</b>
</tag5>
</xsl:copy>
</xsl:template>
<xsl:template match="tag2">
<xsl:copy>zzzzzzzzzz</xsl:copy>
</xsl:template>
The approach with <xsl:apply-templates>
is more flexible than the one with <xsl:copy-of>
: To insert a new element after <tag3>
you could use a template such as:
<xsl:template match="tag3">
<xsl:copy-of select="." />
<tag3-1>zzzzzzzzzz</tag3-1>
</xsl:template>
Upvotes: 1