1
votes

I have xml like follows,

<doc>
    <a ref="style1"><b>Test1</b></a>
    <a ref="style1"><b>Test2</b></a>
    <a ref="style2"><b>Test3</b></a>
</doc>

I need to add new attribute and new node inside <a> nodes which have attribute "style1".

So I wrote following xsl,

//add attribute
<xsl:template match="a[@ref='style1']">
        <xsl:copy>
            <xsl:attribute name="id">myId</xsl:attribute>
        </xsl:copy>
    </xsl:template>

   //add new node
    <xsl:template match="a[@ref='style1']" priority="1">
        <xsl:copy>
            <newNode></newNode>
        </xsl:copy>
        <xsl:next-match/>
    </xsl:template>

I need to create two templates as above (requirement).

but my current output as follows,

<doc>
    <a><newNode/></a><a id="myId"/>
    <a><newNode/></a><a id="myId"/>
    <a ref="style2"><b>Test2</b></a>
</doc>

as you can see, <a> nodes has doubled. and <b>nodes have gone. but m expected output is this,

<doc>
    <a id="myId"><newNode/><b>Test1</b>/a>
    <a id="myId"><newNode/><b>Test2</b>/a>
    <a ref="style2"><b>Test3</b></a>
</doc>

How can I organize my code to get above expected output??

1
Why is it required to have two templates with the same match pattern?michael.hor257k
@michael.hor257k , actually <newNode> must add inside another nodes as well. so correct template would be <xsl:template match="a[@ref='style1' or @ref='mystyle']" priority="1">. this is a sample code.sanjay

1 Answers

2
votes

First, you should only use xsl:copy in one of the templates - otherwise you will be duplicating the node.

Next, you must add attributes before adding any child nodes.

Finally, in order to have both the new attribute and the existing child nodes inside the parent, you must place the relevant instructions inside the xsl:copy element:

XSLT 2.0

<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[@ref='style1']">
    <xsl:attribute name="id">myId</xsl:attribute>
</xsl:template>

<xsl:template match="a[@ref='style1']" priority="1">
    <xsl:copy>
        <xsl:next-match/>
        <newNode/>
        <xsl:apply-templates select="node()"/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

Result

<?xml version="1.0" encoding="UTF-8"?>
<doc>
   <a id="myId">
      <newNode/>
      <b>Test1</b>
   </a>
   <a id="myId">
      <newNode/>
      <b>Test2</b>
   </a>
   <a ref="style2">
      <b>Test3</b>
   </a>
</doc>