XSL: рекурсия против Итерация

#xslt #xslt-2.0 #xpath-2.0

#xslt #xslt-2.0 #xpath-2.0

Вопрос:

Я пытаюсь понять, как XSL обрабатывает for-each . Изначально я написал рекурсивную функцию выбора значений (отфильтровывает все строки, которые не соответствуют шаблону регулярных выражений) следующим образом:

 <!-- Ver.1 -->
<xsl:function name="choose-values">
  <xsl:param name="values" />
  <xsl:param name="pattern" as="xs:string" />

  <xsl:choose>
    <xsl:when test="count($values) = 0" >
      <xsl:sequence select="()" />
    </xsl:when>
    <xsl:otherwise>
      <xsl:variable name="tail"
                    select="choose-values(subsequence($values, 2), $pattern)" />
      <xsl:variable name="value" select="$values[1]" />
      <xsl:sequence select="if (matches($value, $pattern))
                            then ($value, $tail)
                            else $tail" />
    </xsl:otherwise>
  </xsl:choose>
</xsl:function>
  

Затем я наткнулся <xsl:for-each> и переписал его следующим образом:

 <!-- Ver.2 -->
<xsl:function name="choose-values">
  <xsl:param name="values" />
  <xsl:param name="pattern" as="xs:string" />

  <xsl:for-each select="$values">
      <xsl:if test="matches(., $pattern)">
        <xsl:sequence select="." />
      </xsl:if>
  </xsl:for-each>
</xsl:function>
  

Являются ли эти две версии эквивалентными? (мои тесты показывают это). Я пропускаю некоторые крайние случаи в версии 2?

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

Комментарии:

1. Я понимаю, что это не ответ на ваш вопрос, но мне интересно, почему вы просто не используете $values[matches(., $pattern)] . Конечно, нет необходимости писать функцию для фильтрации элементов в последовательности XSLT / XPath 2.0, язык XPath имеет предикаты для этой цели.

2. Ну, это был просто надуманный пример, иллюстрирующий рекурсию и точку итерации. В моем реальном коде функция, применяемая к каждому элементу, сложнее, чем обычная matches() .

Ответ №1:

Да, два образца кажутся эквивалентными. Как правило, вам не нужна рекурсия в XSLT, если обработка одного элемента в последовательности каким-либо образом не зависит от обработки предыдущих элементов. Если каждый элемент обрабатывается независимо от других, вы можете использовать выражения фильтра или выражения сопоставления, одним из примеров которых является xsl:for-each . Преимущество выполнения этого способа (помимо удобочитаемости кода) заключается в том, что вы не навязываете порядок обработки, что дает оптимизатору больше свободы для работы с его магией.

Ответ №2:

Являются ли эти две версии эквивалентными? (мои тесты показывают это). Я пропускаю некоторые крайние случаи в версии 2?

Похоже, они дают одинаковые результаты — трудно сказать, потому что оба фрагмента кода излишне сложны.

Это можно сделать просто:

 <xsl:sequence select="$values[matches(., $pattern)]"/>