Reputation: 23
I need to copy a tree. But for certain nodes (where attr2="yyy") I want to make 2 copies:
Input:
<root>
<element>
<node1 attr1="xxx">copy once</node1>
<node2 attr2="yyy">copy twice, modify attr2 in 2nd copy</node2>
<node3 attr2="yyy" attr3="zzz">copy twice, modify attr2 in 2nd copy</node3>
</element>
</root>
Desired output:
<root>
<element>
<node1 attr1="xxx">copy once</node1>
<node2 attr2="yyy">copy twice, modify attr2 in 2nd copy</node2>
<node2 attr2="changed">copy twice, modify attr2 in 2nd copy</node2>
<node3 attr2="yyy" attr3="zzz">copy twice, modify attr2 in 2nd copy</node3>
<node3 attr2="changed" attr3="zzz">copy twice, modify attr2 in 2nd copy</node3>
</element>
</root>
I'm using this stylesheet:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="node()[@attr2='yyy']">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
<xsl:copy>
<xsl:attribute name="attr2">changed</xsl:attribute>
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
and getting following output:
<root>
<element>
<node1 attr1="xxx">copy once</node1>
<node2 attr2="yyy">copy twice, modify attr2 in 2nd copy</node2>
<node2 attr2="changed">copy twice, modify attr2 in 2nd copy</node2>
<node3 attr2="yyy" attr3="zzz">copy twice, modify attr2 in 2nd copy</node3>
<node3 attr2="changed">copy twice, modify attr2 in 2nd copy</node3>
</element>
</root>
Note that in the second copy of node3 attr3 is missing. If I modify the second template to be applied to nodes and attributes:
<xsl:copy>
<xsl:attribute name="attr2">changed</xsl:attribute>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
then attr2 is not replaced.
I have been trying to figure this out by myself with no success so far. I appreciate any help pointing me in the right direction.
Upvotes: 2
Views: 1176
Reputation: 9627
You are quite close. Only one lien missing.
Add a line to copy all attribute
<xsl:apply-templates select="@*"/>
before changing the attr2 content.
Try this:
<xsl:template match="node()[@attr2='yyy']">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:attribute name="attr2">changed</xsl:attribute>
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
Upvotes: 3