根据xslt 1.0中for-each循环的排序函数计算节点数

时间:2014-02-03 10:31:34

标签: xml xslt xslt-1.0

输入xml具有以下层次结构。

<a>  
 <b>
  <b1>3</b1> 
  <c> 
    <d>
    <d1>13</d1>
    <d2>text1</d2> 
    </d>
    <d>
    <d1>14</d1>
    <d2>text2</d2>
    </d>   
    <d>
    <d1>12</d1>
    <d2>text3</d2> 
    </d>
  </c>  
 </b>  
 <b>
  <b1>2</b1> 
  <c>  
    <d> 
    <d1>11</d1>
    <d2>text5</d2>
    </d>
    <d>
    <d1>10</d1>
    <d2>text4</d2>
    </d>
  </c>  
 </b> 
  ---- and so on.
</a>

我有一个xsl模板,其中一部分看起来像

    <xsl:for-each select="a/b">
    <xsl:sort select="b1" data-type="number"/>
    ----- other mapping---
     <xsl:for-each select="c/d">
     <xsl:sort select="d1" data-type="number"/>
       <xsl:variable name="cnt">
       <xsl:value-of select="count(preceding::../../c/d)"/>
      </xsl:variable>
     ------ other mapping------
     </xsl:for-each>
    </xsl:for-each>

现在,即使应用了sort函数,count函数也遵循输入xml中'd'的顺序,而不是基于for-each语句中'd'的升序排序。 for-eg在元素b的循环2中,即b [position()= 2]我得到cnt = 3虽然它应该是2。请建议。

1 个答案:

答案 0 :(得分:0)

前面的:: axis只查看文档顺序中的节点 - 它们在输入中的实际顺序。它不需要考虑当前序列或当前排序顺序。

如果你真的想要计算在当前输入之前有多少<d>个元素,那么你可以知道在它之前的每个元素应该具有比排序键更低的值。目前的一个:

<xsl:variable name="d1" select="number(d1)" />
<xsl:value-of select="count(../d[number(d1) &lt; $d1])" />

但是xslt中已经存在一个函数,它将以for-each循环的排序顺序为您提供当前节点的位置,即position()函数。它开始计数为1,因此如果您想知道当前节点之前有多少节点,则需要减去一个:

<xsl:for-each select="a/b">
    <xsl:sort select="b1" data-type="number" />
    ----- other mapping---
    <xsl:for-each select="c/d">
        <xsl:sort select="d1" data-type="number" />
        <xsl:variable name="cnt">
            <xsl:value-of select="position() - 1" />
        </xsl:variable>
        ------ other mapping------
    </xsl:for-each>
</xsl:for-each>

这是来自xslt 1.1规范,它描述了它比xslt 1.0规范更好,但在xslt 1.0中也是如此:

  

[上下文位置是上下文项目的位置   当前正在处理的项目序列。每当它发生变化   上下文项目更改。当诸如xsl:apply-templates之类的指令时   或者xsl:for-each用于处理项目序列,即第一项   在序列中处理上下文位置为1,第二个   上下文位置为2的项目,依此类推。]上下文位置为   由XPath表达式position()返回。

从你的进一步评论看来,你想要一个代表两个for循环中当前节点整体顺序的数字,以for循环的排序顺序。

您可以使用我的第一种方法:通过使用'&lt;'比较值来计算排序顺序中此节点之前的节点。

然后你的XSL变成:

<xsl:for-each select="a/b">
    <xsl:sort select="b1" data-type="number" />
    ----- other mapping---
    <xsl:for-each select="c/d">
        <xsl:sort select="d1" data-type="number" />
        <xsl:variable name="me" select="." />
        <xsl:variable name="cnt">
            <xsl:value-of select="count(../d[number(d1) &lt; number($me/d1)]) + count(../../../b/c/d[number(../../b1) &lt; number($me/../../b1)])" />
        </xsl:variable>
        ------ other mapping------
    </xsl:for-each>
</xsl:for-each>

我认为这就是你所描述的。 如果您还想要其他东西,那么我认为您的问题不是很明确 - 根据您的示例输入文件,请准确描述您要查找的结果。