【问题标题】:xsl recursive loop node by indexxsl 递归循环节点按索引
【发布时间】:2010-12-17 15:00:01
【问题描述】:

我创建了一个递归模板,用于从我的 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,直到我拥有所需的数量。

【问题讨论】:

    标签: xpath recursion xslt loops indexing


    【解决方案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.1 相对于item.0 的相对位置为 1。 (基本上,这和上面的一样,只是沿着(隐式)child:: 轴计算。)

    单独使用时,如下所示:

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

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

    【讨论】:

      【解决方案2】:

      我会使用 和 position() 而不是递归。

      【讨论】:

      • 道歉 - 没有注意就盲目地给出了和你一样的答案。
      【解决方案3】:

      我不太明白为什么需要递归模板来执行此操作。您可以使用 来实现这一点。 (我更改了元素名称以使其合法) 例如:

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

      你可以使用你想要的选择属性,如果你的输入比你的例子更复杂,你可以在 for-each 中包含一个

      【讨论】:

      • 对不起,也许我应该添加另一个细节。我真正想要的是分组输出项目,我想在输出之前对组进行汇总。但我需要先将它们分组到一个片段树中,以便我可以对每个组执行功能。这就是我的循环所做的。所以我只需要根据索引获取到合适的节点即可。或者这是不可能的?我是菜鸟。
      • 您使用的是 XSLT 版本 1 还是 2?我怀疑 XSLT 2.0 会让这件事变得更容易 - XSLT 2.0 中有分组语句,您需要在 1.0 中滚动自己的语句
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-30
      相关资源
      最近更新 更多