xsl索引的递归循环节点

时间:2009-11-17 20:52:37

标签: xpath recursion xslt loops indexing

我创建了一个递归模板,用于从我的XML中获取前n个项目。

它使用索引(计数器),就像我在for循环中一样。现在我如何使用索引从我的XML中获取节点?

我尝试过[position()= $ index]但是在尝试在XML层次结构中获取更深层节点时,它有奇怪的行为。

如果我有XML,例如:

<0>
 <1>
  <2>item</2>
  <2>item</2>
  <2>item</2>
  <2>item</2>
  <2>item</2>
  <2>item</2>
 </1>
</0>

我希望能够计算并复制2,直到我有我想要的数量。

3 个答案:

答案 0 :(得分:1)

你说你想要以n为一组处理你的元素。以下XSLT 1.0解决方案可以实现:

<xsl:stylesheet 
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
  <xsl:param name="pGroupCount" select="3" />

  <xsl:template match="/lvl-0">
    <xsl:copy>
      <!-- select the nodes that start a group -->
      <xsl:apply-templates mode="group" select="
        lvl-1/lvl-2[position() mod $pGroupCount = 1]
      " />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="lvl-2" mode="group">
    <!-- select the nodes belong to the current group -->
    <xsl:variable name="current-group" select="
      . | following-sibling::lvl-2[position() &lt; $pGroupCount]
    " />
    <!-- output the current group, you can also do calculations with it -->
    <group id="{position()}">
      <xsl:copy-of select="$current-group" />
    </group>
  </xsl:template>
</xsl:stylesheet>

应用于此输入文档时:

<lvl-0>
 <lvl-1>
  <lvl-2>item.0</lvl-2>
  <lvl-2>item.1</lvl-2>
  <lvl-2>item.2</lvl-2>
  <lvl-2>item.3</lvl-2>
  <lvl-2>item.4</lvl-2>
  <lvl-2>item.5</lvl-2>
  <a>foo</a><!-- to prove that position() calculations still work -->
  <lvl-2>item.6</lvl-2>
  <lvl-2>item.7</lvl-2>
  <lvl-2>item.8</lvl-2>
  <lvl-2>item.9</lvl-2>
 </lvl-1>
</lvl-0>

生成以下输出:

<lvl-0>
  <group id="1">
    <lvl-2>item.0</lvl-2>
    <lvl-2>item.1</lvl-2>
    <lvl-2>item.2</lvl-2>
  </group>
  <group id="2">
    <lvl-2>item.3</lvl-2>
    <lvl-2>item.4</lvl-2>
    <lvl-2>item.5</lvl-2>
  </group>
  <group id="3">
    <lvl-2>item.6</lvl-2>
    <lvl-2>item.7</lvl-2>
    <lvl-2>item.8</lvl-2>
  </group>
  <group id="4">
    <lvl-2>item.9</lvl-2>
  </group>
</lvl-0>

要理解这一点,您必须知道position()的工作原理。使用时如下:

lvl-1/lvl-2[position() mod $pGroupCount = 1]

它指的是lvl-2节点在其各自(!)父节点内的位置。在这种情况下,只有一个父级,因此item.0的位置为1,item.9的位置为10。

当像这样使用时:

following-sibling::lvl-2[position() &lt; $pGroupCount]

它指的是following-sibling::轴上的相对位置。在这种情况下,item.1item.0方面的相对位置为1。 (基本上,这与上面的相同,只是沿着(隐含的)child::轴计算。)

单独使用时,如:

<group id="{position()}">

它指的是当前正在处理的批处理中当前节点的位置。在我们的例子中,“批处理”由启动组的节点(item.0item.3item.6item.9)组成,因此从1到4。

答案 1 :(得分:0)

我会使用&lt; xsl:for-each ...&gt;与position()而不是递归。

答案 2 :(得分:0)

我不太明白为什么你需要一个递归模板才能做到这一点。您可以使用&lt; xsl:for-each&gt;为达到这个。 (我更改了元素名称以使其合法) 例如:

<xsl:variable name='n' select='10'/>
<xsl:for-each select='two[position() &lt; $n]'>
    <!-- do whatever you need to do -->
</xsl:for-each>

您可以使用所需的选择属性,并且可以包含&lt; xsl:sort&gt;如果您的输入比您的示例更复杂,则在for-each中。