XSLT: цикл от 1 до 60 - PullRequest
       17

XSLT: цикл от 1 до 60

35 голосов
/ 31 января 2012

Каков наилучший способ зацикливания в XSLT от 1 до 60?Я исследую сеть, есть несколько шаблонов для этого, есть ли другой способ, например, встроенная функция?

Ответы [ 5 ]

45 голосов
/ 31 января 2012

В XSLT 2.0,

<xsl:for-each select="1 to 60">...</xsl:for-each>

Но я предполагаю, что вы должны использовать XSLT 1.0, иначе вы бы не спрашивали.

В XSLT 1.0 вы должны использовать рекурсию: aшаблон, который вызывает себя со счетчиком, который увеличивается при каждом вызове, и рекурсия завершается при достижении требуемого значения.

В качестве альтернативы есть обходной путь в XSLT 1.0: при условии, что ваш исходный документ содержит не менее 60 узлов, вы можетеделать

<xsl:for-each select="(//node())[60 >= position()]">...</xsl:for-each>
25 голосов
/ 31 января 2012

Проблема с простой рекурсией при обработке длинных последовательностей заключается в том, что часто места для стека вызовов становится недостаточно и обработка заканчивается из-за переполнения стека. Обычно это происходит с длиной последовательности> = 1000.

Общая методика, позволяющая избежать этого (реализуемая любым процессором XSLT, даже если он не распознает хвостовую рекурсию), - это рекурсия в стиле DVC (разделяй и властвуй) .

Вот пример преобразования, которое успешно печатает числа от 1 до 1000000 (1M):

<xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output method="text"/>

     <xsl:template match="/">
      <xsl:call-template name="displayNumbers">
        <xsl:with-param name="pStart" select="1"/>
        <xsl:with-param name="pEnd" select="1000000"/>
      </xsl:call-template>
     </xsl:template>

     <xsl:template name="displayNumbers">
      <xsl:param name="pStart"/>
      <xsl:param name="pEnd"/>

      <xsl:if test="not($pStart > $pEnd)">
       <xsl:choose>
        <xsl:when test="$pStart = $pEnd">
          <xsl:value-of select="$pStart"/>
          <xsl:text>&#xA;</xsl:text>
        </xsl:when>
        <xsl:otherwise>
          <xsl:variable name="vMid" select=
           "floor(($pStart + $pEnd) div 2)"/>
          <xsl:call-template name="displayNumbers">
           <xsl:with-param name="pStart" select="$pStart"/>
           <xsl:with-param name="pEnd" select="$vMid"/>
          </xsl:call-template>
          <xsl:call-template name="displayNumbers">
           <xsl:with-param name="pStart" select="$vMid+1"/>
           <xsl:with-param name="pEnd" select="$pEnd"/>
          </xsl:call-template>
        </xsl:otherwise>
       </xsl:choose>
      </xsl:if>
     </xsl:template>
</xsl:stylesheet>

При применении к любому документу XML (не используется) это преобразование дает желаемый результат - все числа от 1 до 1000000.

Вы можете использовать / адаптировать это преобразование для любой задачи, которая должна "сделать что-то N раз".

3 голосов
/ 22 мая 2015

Очень простая проверка внутри цикла foreach

<xsl:if test="$maxItems > position()">
    do something
</xsl:if>

На основе ответа Дмитрия Новатчева .

Пример:

<xsl:variable name="maxItems" select="10" />
<xsl:variable name="sequence" select="any-sequence"/>

<xsl:for-each select="$sequence">

    <!-- Maybe sort first -->
    <xsl:sort select="@sort-by" order="descending" />

    <!-- where the magic happens -->
    <xsl:if test="$maxItems > position()">
        do something
    </xsl:if>
</xsl:for-each>
0 голосов
/ 22 марта 2019

Базовый пример для V1.0 с использованием рекурсии будет выглядеть так:

<xsl:template match="/">
<Root>
      <!-- Main Call to MyTemplate -->
     <xsl:call-template name="MyTemplate" />
</Root>
</xsl:template>

<xsl:template name="MyTemplate">
  <xsl:param name="index" select="1" />
  <xsl:param name="maxValue" select="60" />

  <MyCodeHere>
     <xsl:value-of select="$index"/>
  </MyCodeHere>

  <!-- &lt; represents "<" for html entities -->
  <xsl:if test="$index &lt; $maxValue">
    <xsl:call-template name="MyTemplate">
        <xsl:with-param name="index" select="$index + 1" />
        <xsl:with-param name="total" select="$maxValue" />
    </xsl:call-template>
  </xsl:if>
</xsl:template>
0 голосов
/ 31 января 2012

XSLT работает на основе шаблонов, и вам понадобится шаблон для запуска этого цикла.

Вам нужно будет создать шаблон, получающий начальное и конечное значения, и внутри него сделать рекурсивный вызов, вычисляя с помощью start + 1. Когда $ start равен $ end, вы возвращаете свой шаблон без повторного вызова.

На практике: http://www.ibm.com/developerworks/xml/library/x-tiploop/index.html

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