向节点添加属性

时间:2011-01-28 04:29:29

标签: xslt xslt-2.0

如果子节点值等于某个字符串,我正在尝试向节点添加属性。

我有一个main.xml文件

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

因此,假设国家标识等于32,则应将属性country = 32添加到Employee节点。输出应如下所示:

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

我正在使用以下脚本,但收到的错误是在包含元素的子元素之后无法创建属性节点。:

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>

任何帮助将不胜感激。我们也可以将countryid作为逗号分隔值传递,以便我可以传递32,100,然后它应该为所有匹配的节点添加属性。

感谢。

2 个答案:

答案 0 :(得分:12)

第1部分

  

所以,假设国家ID是   等于32然后它应该添加   属性country = 32到Employee节点。

此转化

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

应用于提供的XML文档

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

生成想要的正确结果

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

<强>解释

  1. identity rule用于按原样复制每个节点。使用和覆盖标识规则(模板)是最基本和最强大的XSLT设计模式。

  2. 只有一个模板会覆盖特定节点的身份规则 - Employee元素,其中countryid子元素具有字符串值(转换为数字) )32.此模板向countryid元素添加Employee属性,并应用模板以恢复身份规则的活动,并按原样复制其他所有内容。

  3. 第2部分。

      

    我们也可以将countryid作为逗号传递   分离的值,以便我可以通过   32,100然后它应该添加   属性到所有匹配的节点

    此转化

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

    应用于同一XML文档(上图)时,会生成所需的正确结果

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

答案 1 :(得分:5)

除了Dimitre的好答案外,还有一个XSLT 2.0样式表:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:param name="pCountry" select="'32,100'"/>
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="Employee[countryid = tokenize($pCountry,',')]">
        <Employee countryid="{countryid}">
            <xsl:apply-templates select="@*|node()"/>
        </Employee>
    </xsl:template>
</xsl:stylesheet>

输出:

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

注意:与序列中的存在性比较,模式中的参数/变量引用。

假设countryid始终是第一个孩子的其他方法:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:strip-space elements="*"/>
    <xsl:param name="pCountry" select="'32,100'"/>
    <xsl:template match="node()|@*" name="identity">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="countryid[. = tokenize($pCountry,',')]">
        <xsl:attribute name="countryid">
            <xsl:value-of select="."/>
        </xsl:attribute>
        <xsl:call-template name="identity"/>
    </xsl:template>
</xsl:stylesheet>

注意:现在xsl:strip-space指令非常重要(避免在属性之前输出文本节点)