1

我在示例 xslt 上有这段代码,我无法准确地制作这部分。我想了解这部分seq_no[/*/*/seq_no[@num = following::seq_no/@num]]。任何的想法?

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

1 回答 1

2

您正在尝试理解表达式seq_no[/*/*/seq_no[@num = following::seq_no/@num]]。它有助于将其分解为单独的部分。考虑以下:

/*/*/seq_no

因为此表达式以 a 开头/,所以这是一个绝对路径,并且将匹配文档中作为 XML 根元素的孙子元素的任何seq_no元素。您使用以下 xpath 表达式对其进行量化:

[@num = following::seq_no/@num]

因此,它正在寻找一个seq_no元素,其num属性与文档中紧随其后的另一个seq_no元素具有相同的值。即它在 XML 中是否有重复的属性。

但它在这里是绝对路径这一事实意味着它与您匹配的seq_no 无关。因此,如果文档中的任何位置确实存在重复项,则表达式[/*/*/seq_no[@num = following::seq_no/@num]将返回 true,因此您的模板将匹配文档中的所有seq_no元素。

请注意,这不是很有效,因为您正在评估文档中每个seq_no元素的表达式,即使它对于所有元素总是具有相同的值。最好一次将其评估为变量,然后在模板匹配中使用xsl:choose来确定是否需要更新属性值。

试试这个 XSLT,例如

<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:variable name="duplicate" select="/*/*/seq_no[@num = following::seq_no/@num]"/>

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

   <xsl:template match="seq_no/@num">
      <xsl:choose>
         <xsl:when test="$duplicate">
            <xsl:attribute name="num">
               <xsl:number count="seq_no" level="any"/>
               <xsl:value-of select="concat('[', ., ']')"/>
            </xsl:attribute>
         </xsl:when>
         <xsl:otherwise>
            <xsl:copy/>
         </xsl:otherwise>
      </xsl:choose>
   </xsl:template>
</xsl:stylesheet>

请注意,我已更改模板以匹配此处的num属性,因为这是您实际转换的 XML 的唯一部分。另外,我也在使用xsl:number进行计数。

于 2013-08-26T08:45:11.810 回答