Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
412 views
in Technique[技术] by (71.8m points)

xslt - adding attribute to the node

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Part 1.

So let's say if the country id is equal to 32 then it should add attribute country=32 to Employee node.

This transformation:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="Employee[countryid=32]">
  <Employee countryid="{countryid}">
   <xsl:apply-templates select="@*|node()"/>
  </Employee>
 </xsl:template>
</xsl:stylesheet>

when applied on the provided XML document:

<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>

produces the wanted, correct result:

<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>

Explanation:

  1. 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.

  2. There is only one template that overrides the identity rule for specific nodes -- Employee elements that have a countryid child with string value (converted to number) 32. This template adds a countryid attribute to the Employee element and applies templates to resume the activity of the identity rule and copy everything else as-is.

Part 2.

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

This transformation:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:param name="pIds" select="'32,100'"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="Employee">
  <Employee>
   <xsl:if test=
     "contains(concat(',',$pIds,','),
               concat(',',countryid,',')
               )">
    <xsl:attribute name="countryid">
      <xsl:value-of select="countryid"/>
    </xsl:attribute>
   </xsl:if>
   <xsl:apply-templates select="@*|node()"/>
  </Employee>
 </xsl:template>
</xsl:stylesheet>

when applied to the same XML document (above), produces the wanted, correct result:

<Employees>
   <Employee countryid="32">
      <countryid>32</countryid>
      <id name="id">1</id>
      <firstname>ABC</firstname>
      <lastname>XYZ</lastname>
   </Employee>
   <Employee countryid="100">
      <countryid>100</countryid>
      <id name="id">2</id>
      <firstname>ddd</firstname>
      <lastname>ggg</lastname>
   </Employee>
</Employees>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

56.8k users

...