检查重复的属性值并添加前缀

时间:2012-08-28 19:06:26

标签: xslt

我有一个xml doc:

<xml>
   <staff>
       <seq_no num="0">0</seq_no>
       <name>xyz</name>
   </staff>
   <staff>
       <seq_no num="1">1</seq_no>
       <name>xyz</name>
   </staff>
   <staff>
      <seq_no num="1">2</seq_no>
      <name>abc</name>
   </staff>
   <staff>
      <seq_no num="3">3</seq_no>
      <name>abc</name>
   </staff>
 </xml>

如果seq_no中的任何一个相同,我想在seq_no / @ num中添加数字。 如果没有重复,则不会添加任何内容。

上面的输出应该是:

    <xml>
     <staff>  
          <seq_no num="[1]1">0</seq_no>
          <name>xyz</name>
       </staff>
     <staff>
          <seq_no num="[2]1">1</seq_no>
          <name>xyz</name>
     </staff>
     <staff>
         <seq_no num="[3]1">2</seq_no>
         <name>abc</name>
      </staff>
     <staff>
         <seq_no num="[4]3">3</seq_no>
         <name>abc</name>
      </staff>
</xml>

分别将[1],[2],[3],[4]添加到seq_no / @ num。我开始使用匹配模板这样的工作

<xsl:template match="seq_no/num">
<seq_no>
  <xsl:attribute name="num">
    <xsl:text>[</xsl:text><xsl:number select="." format="1" level="any"  /><xsl:text>]</xsl:text>
    <xsl:value-of select="@num"></xsl:value-of>
  </xsl:attribute>
<xsl:value-of select="."></xsl:value-of>
</seq_no>
</xsl:template>

但在控制位置时遇到麻烦以及如何检查其他seq_no的重复数量......

输入没有任何重复的数字:

 <xml>
   <staff>
       <seq_no num="0">0</seq_no>
       <name>xyz</name>
   </staff>
   <staff>
       <seq_no num="1">1</seq_no>
       <name>xyz</name>
   </staff>
   <staff>
      <seq_no num="2">2</seq_no>
      <name>abc</name>
   </staff>
   <staff>
      <seq_no num="3">3</seq_no>
      <name>abc</name>
   </staff>
 </xml>.

输出应与输入无需处理相同。

 <xml>
   <staff>
       <seq_no num="0">0</seq_no>
       <name>xyz</name>
   </staff>
   <staff>
       <seq_no num="1">1</seq_no>
       <name>xyz</name>
   </staff>
   <staff>
      <seq_no num="1">2</seq_no>
      <name>abc</name>
   </staff>
   <staff>
      <seq_no num="3">3</seq_no>
      <name>abc</name>
   </staff>
 </xml>

2 个答案:

答案 0 :(得分:1)

逻辑似乎仍然不符合您的输入/输出示例,但这是我认为您正在尝试做的...

XML输入

<xml>
    <staff>
        <seq_no num="0">0</seq_no>
        <name>xyz</name>
    </staff>
    <staff>
        <seq_no num="1">1</seq_no>
        <name>xyz</name>
    </staff>
    <staff>
        <seq_no num="1">2</seq_no>
        <name>abc</name>
    </staff>
    <staff>
        <seq_no num="3">3</seq_no>
        <name>abc</name>
    </staff>
</xml>

XSLT 1.0

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

    <!--Check for any duplicates in the doc.-->
    <xsl:variable name="vDups" select="boolean(//seq_no[@num=preceding::seq_no/@num])"/>

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

    <xsl:template match="seq_no">
        <xsl:copy>
            <xsl:choose>
                <xsl:when test="$vDups">
                    <xsl:attribute name="num">
                        <xsl:text>[</xsl:text>
                        <xsl:number level="any"/>
                        <xsl:text>]</xsl:text>
                        <xsl:value-of select="."/>                      
                    </xsl:attribute>
                    <xsl:apply-templates select="@*[not(name()='num')]|node()"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:apply-templates select="@*|node()"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

XML输出

<xml>
   <staff>
      <seq_no num="[1]0">0</seq_no>
      <name>xyz</name>
   </staff>
   <staff>
      <seq_no num="[2]1">1</seq_no>
      <name>xyz</name>
   </staff>
   <staff>
      <seq_no num="[3]2">2</seq_no>
      <name>abc</name>
   </staff>
   <staff>
      <seq_no num="[4]3">3</seq_no>
      <name>abc</name>
   </staff>
</xml>

可选,XSLT 2.0模板更换更清洁:

<xsl:template match="seq_no[$vDups]">
    <xsl:copy>
        <xsl:attribute name="num">
            <xsl:text>[</xsl:text>
            <xsl:number level="any"/>
            <xsl:text>]</xsl:text>
            <xsl:value-of select="."/>                      
        </xsl:attribute>
        <xsl:apply-templates select="@*[not(name()='num')]|node()"/>
    </xsl:copy>
</xsl:template>

答案 1 :(得分:1)

此转化

<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="seq_no[/*/*/seq_no[@num = following::seq_no/@num]]">
  <seq_no num="[{count(preceding::seq_no)+1}]{.}">
   <xsl:apply-templates/>
  </seq_no>
 </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档

<xml>
    <staff>
        <seq_no num="0">0</seq_no>
        <name>xyz</name>
    </staff>
    <staff>
        <seq_no num="1">1</seq_no>
        <name>xyz</name>
    </staff>
    <staff>
        <seq_no num="1">2</seq_no>
        <name>abc</name>
    </staff>
    <staff>
        <seq_no num="3">3</seq_no>
        <name>abc</name>
    </staff>
</xml>

生成想要的正确结果

<xml>
   <staff>
      <seq_no num="[1]0">0</seq_no>
      <name>xyz</name>
   </staff>
   <staff>
      <seq_no num="[2]1">1</seq_no>
      <name>xyz</name>
   </staff>
   <staff>
      <seq_no num="[3]2">2</seq_no>
      <name>abc</name>
   </staff>
   <staff>
      <seq_no num="[4]3">3</seq_no>
      <name>abc</name>
   </staff>
</xml>

当对此XML文档应用相同的转换(上面)时(没有@num重复):

<xml>
    <staff>
        <seq_no num="0">0</seq_no>
        <name>xyz</name>
    </staff>
    <staff>
        <seq_no num="1">1</seq_no>
        <name>xyz</name>
    </staff>
    <staff>
        <seq_no num="2">2</seq_no>
        <name>abc</name>
    </staff>
    <staff>
        <seq_no num="3">3</seq_no>
        <name>abc</name>
    </staff>
</xml>

再次生成想要的正确结果:

<xml>
  <staff>
    <seq_no num="0">0</seq_no>
    <name>xyz</name>
  </staff>
  <staff>
    <seq_no num="1">1</seq_no>
    <name>xyz</name>
  </staff>
  <staff>
    <seq_no num="2">2</seq_no>
    <name>abc</name>
  </staff>
  <staff>
    <seq_no num="3">3</seq_no>
    <name>abc</name>
  </staff>
</xml>