Juan Pablo Rostra
Juan Pablo Rostra

Reputation: 23

XSL - Copy tree, copying some nodes twice and changing attribute in second copy

I need to copy a tree. But for certain nodes (where attr2="yyy") I want to make 2 copies:

  1. First one "as it is"
  2. Second one modifying attr2 value.

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

Answers (1)

hr_117
hr_117

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

Related Questions