I am trying to add an attribute to the node if the child node value is equal to some string.
I have a main.xml file
<Employees>
<Employee>
<countryid>32</countryid>
<id name="id">1</id>
<firstname >ABC</firstname>
<lastname >XYZ</lastname>
</Employee>
<Employee>
<countryid>100</countryid>
<id name="id">2</id>
<firstname >ddd</firstname>
<lastname >ggg</lastname>
</Employee>
</Employees>
So let's say if the country id is equal to 32 then it should add attribute country=32 to Employee node. The output should be like below :
output.xml
<Employees>
<Employee countryid="32">
<countryid>32</countryid>
<id name="id">1</id>
<firstname >ABC</firstname>
<lastname >XYZ</lastname>
</Employee>
<Employee>
<countryid>100</countryid>
<id name="id">2</id>
<firstname >ddd</firstname>
<lastname >ggg</lastname>
</Employee>
</Employees>
I am using the following script but getting error that An attribute node cannot be create after the children of containing element.:
Transform.xsl
<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="Employees/Employee/countryid[.=32']">
<xsl:attribute name="countryid">32</xsl:attribute>
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
Any help will be appreciated. Also can we pass countryid as comma seprated values so that i can pass 32,100 and then it should add attribute to all the matching nodes.
Thanks.
In addition to Dimitre's good answer, an XSLT 2.0 stylesheet:
Output:
Note: Existencial comparison with sequence, param/variable reference in patterns.
Other approach assuming
countryid
is always first child:Note: Now
xsl:strip-space
instruction is important (avoids output text node before attribute)Part 1.
This transformation:
when applied on the provided XML document:
produces the wanted, correct result:
Explanation:
The identity rule is used to copy every node as-is. Using and overriding the identity rule (template) is the most fundamental and powerful XSLT design pattern.
There is only one template that overrides the identity rule for specific nodes --
Employee
elements that have acountryid
child with string value (converted to number) 32. This template adds acountryid
attribute to theEmployee
element and applies templates to resume the activity of the identity rule and copy everything else as-is.Part 2.
This transformation:
when applied to the same XML document (above), produces the wanted, correct result: