Книга: Технология XSLT

Цикл for

Цикл for

Частным случаем цикла while является цикл for. В разных языках программирования for имеет различную семантику; мы будем рассматривать циклы for вида

for (int i = 0; i < n; i++) { ... }

в языках Java и С или

for i := 0 to n-1 do begin ... end;

в Pascal. Иными словами, нас будет интересовать циклическое выполнение определенных действий при изменении значения некоторой переменной (называемой иногда индексом цикла) в интервале целых чисел от 0 до n включительно.

Цикл for может быть определен через while с использованием следующих условных и изменяющих функций:

условие($i, $n,$x1,...,$хk)      :: = ($i < $n)
функцияi($i, $n, $x1, ... , $xk) ::= ($i + 1)
функцияn($i, $n, $x1, ..., $xk)  :: = ($n)

Шаблон цикла for в общем виде будет выглядеть как.

Листинг 11.12. Шаблон цикла for в общем виде

<xsl:template name="for">
 <xsl:param name="i" select="0"/>
 <xsl:param name="n"/>
 <!-- Другие переменные -->
 <xsl:param name="x1"/>
 <!-- ... -->
 <xsl:param name="xk"/>
 <xsl:choose>
  <xsl:when test="$i &lt; $n">
   <!-- Действия -->
   <xsl:call-template name="for">
    <xsl:with-param name="i" select="$i + 1"/>
    <xsl:with-param name="n" select="$n"/>
    <!-- Другие переменные -->
    <xsl:with-param" name="x1" select функция1($i, $n, $x1, ..., $xk) "/>
    <!-- ... -->
    <xsl:with-param name="xk" select="функцияk($i, $n, $x1, ..., $xk)"/>
   </xsl:call-template>
  </xsl:when>
  <xsl:otherwise>
   <xsl:value-of select="результат($i,$n,$x1,...,$xk)"/>
  </xsl:otherwise>
 </xsl:choose>
</xsl:template>

В качестве примера цикла for приведем шаблон, вычисляющий n первых чисел Фибоначчи.

Числа Фибоначчи — это рекуррентная последовательность вида

1 1 2 3 5 8 13 21 ...

и так далее, где каждое последующее число определяется как сумма двух предыдущих.

Для вычисления n первых чисел Фибоначчи мы можем использовать две переменные current и last, соответствующих текущему число и числу, полученному на предыдущем шаге соответственно. Функции, переопределяющие эти переменные, совершенно очевидны:

функцияlast($i, $n, $last, $current)   ::= ($current)
функцияcurrent($i, $n, $last, $current) ::= ($current + $last)

Поскольку в данном случае нам не нужно возвращать результат, нужно лишь циклически выводить очередное число Фибоначчи, шаблон for может быть немного упрощен использованием элемента xsl:if вместо xsl:choose.

Листинг 11.13. Шаблон, вычисляющий числа Фибоначчи

<xsl:template name="for">
 <xsl:param name="i" select="0"/>
 <xsl:param name="n"/>
 <xsl:param name="last" select="0"/>
 <xsl:param name="current" select="1"/>
 <xsl:if test="$i &lt; $n">
  <xsl:text> </xsl:text>
  <xsl:value-of select="$current"/>
  <xsl:call-template name="for">
   <xsl:with-param name="i" select="$i + 1"/>
   <xsl:with-param name="n" select="$n"/>
   <xsl:with-param name="last" select="$current"/>
   <xsl:with-param name="current" select="$last + $current"/>
  </xsl:call-template>
 </xsl:if>
/xsl:template>

Вызванный в основном шаблоне как:

<xsl:template match="/">
 <xsl:call-template name="for">
  <xsl:with-param name="n" select="6"/>
 </xsl:call-template>
</xsl:template>

этот шаблон создаст в выходящем документе последовательность:

1 1 2 3 5 8

Приведем еще более простой пример, в котором элемент option выводится заданное число раз.

Листинг 11.14. Вывод 10 элементов option

<xsl:stylesheet
 version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform'">
 <xsl:template match="/">
  <xsl:call-template name="for">
   <xsl:with-param name="n" select="10"/>
  </xsl:call-template>
 </xsl:template>
 <xsl:template name="for">
  <xsl:param name="i" select="0"/>
  <xsl:param name="n"/>
  <xsl:if test="$i &lt; $n">
   <option>
    <xsl:value-of select="$i"/>
   </option>
   <xsl:call-template name="for">
    <xsl:with-param name="i" select="$i + 1"/>
    <xsl:with-param name="n" select="$n"/>
   </xsl:call-template>
  </xsl:if>
 </xsl:template>
</xsl:stylesheet>

Листинг 11.15 Выходящий документ

<option>0</option>
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
<option>6</option>
<option>7</option>
<option>8</option>
<option>9</option>

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

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

Оглавление книги

Оглавление статьи/книги

Генерация: 0.032. Запросов К БД/Cache: 0 / 0
поделиться
Вверх Вниз