XSL рекурсивный цикл узел по индексу - PullRequest
0 голосов
/ 17 ноября 2009

Я создал рекурсивный шаблон для получения первых n элементов из моего XML.

Он использует индекс (счетчик) так же, как в цикле 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 ]

1 голос
/ 18 ноября 2009

Вы говорите, что хотите обработать свои элементы в группах из 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 будет иметь относительную позицию 1 относительно item.0. (По сути, это то же самое, что и выше, которое учитывается вдоль (неявной) child:: оси.)

При самостоятельном использовании, как здесь:

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

относится к позиции текущего узла в пакете, который обрабатывается в данный момент. В нашем случае «пакет» состоит из узлов, которые начинают группу (item.0, item.3, item.6, item.9), поэтому он идет от 1 до 4.

0 голосов
/ 18 ноября 2009

Я не совсем понимаю, зачем вам нужен рекурсивный шаблон для этого. Вы можете использовать для достижения этой цели. (Я изменил имя элемента, чтобы сделать его легальным) Например:

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

Вы можете использовать нужный атрибут select и включить в for-each, если ваш ввод более сложный, чем ваш пример.

0 голосов
/ 18 ноября 2009

Я бы использовал вместе с position () вместо рекурсии.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...