Книга: XSLT
Рекурсивный вызов шаблонов
Рекурсивный вызов шаблонов
Эта тема предназначена, главным образом, для программистов, поскольку здесь я буду пользоваться XSLT как языком программирования. В частности, я реализую вызов именованным шаблоном самого себя, то есть рекурсивный вызов. Классический пример рекурсии — вычисление факториала: например, факториал 6, что записывается как 6!
, равен 6*5*4*3*2*1
, или 720
.
При реализации рекурсии в настоящем языке программирования создается функция — например, factorial
, которая вызывается со значением 6: factorial(6)
. Факториал 6 вычисляется как 6 * factorial(5)
, поэтому функции нужно лишь умножить на 6 результат вызова самой себя со значением 5, то есть factorial(5)
.
Далее, factorial(5)
— это 5*factorial(4)
, поэтому функция снова вызывает сама себя, чтобы вычислить значение factorial(4)
. Этот процесс продолжается до вычисления factorial(1)
, а мы знаем, что 1! — это просто 1, поэтому factorial(1)
возвращает 1. С этого момента управление последовательно возвращается на все предыдущие этапы, в результате чего будет вычислено выражение 1*2*3*4*5*6
, или 720
, что составляет 6!
.
Кажется, что в таком языке стилей, как XSLT, реализовать подобное невозможно. Тем не менее, это можно сделать, по крайней мере, в XSLT 1.0. Основная идея состоит в том, что значение, возвращаемое шаблоном, можно сохранять в переменной, если шаблон вызывается внутри элемента <xsl:variable>
, в котором объявляется эта переменная. Пусть, например, у нас есть именованный шаблон factorial
, и мы хотим вычислить 6!
. Тогда шаблону можно передать значение 6 при помощи элемента <xsl:with-param>
и присвоить строковое значение результата переменной result
, которое я затем показываю:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:variable name="result">
<xsl:call-template name="factorial">
<xsl:with-param name="value" select="6"/>
</xsl:call-template>
</xsl:variable>
6! = <xsl:value-of select="$result"/>
</xsl:template>
.
.
.
Следующий пример демонстрирует, как можно реализовать шаблон factorial
, чтобы для вычисления факториала он вызывал сам себя. На языке программирования я мог бы написать рекурсивный вызов как n!=n*factorial(n-1)
, но у нас нет оператора присваивания; поэтому, когда я вычисляю factorial(n-1)
, я сохраняю это значение в новой переменной temp
и на каждом шаге возвращаю значение n*$temp
:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:variable name="result">
<xsl:call-template name="factorial">
<xsl:with-param name="value" select="6"/>
</xsl:call-template>
</xsl:variable>
6! = <xsl:value-of select="$result"/>
</xsl:template>
<xsl:template name="factorial">
<xsl:param name="value"/>
<xsl:choose>
<xsl:when test="$value=1">
<xsl:value-of select="1"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="temp">
<xsl:call-template name="factorial">
<xsl:with-param name="value" select="$value - 1"/>
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="$temp * $value"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Вот результирующий документ:
<?xml version="1.0" encoding="utf-8"?>
6! = 720
Как видите, это можно сделать, по крайней мере, в XSLT 1.0, в котором разрешены использованные здесь фрагменты результирующего дерева.
- Вызов хранимых процедур InterBase с использованием стандартного синтаксиса ODBC
- Системные вызовы и драйверы устройств
- Определение необходимого системного вызова
- Удаление шаблонов узлов STP
- Системные вызовы управления процессорной привязкой
- Вызовы функций
- Другие системные вызовы для управления файлами
- Вызов pipe
- Вызов справки из приложений
- Практическая работа 36. Использование шаблонов и тем
- 21.4 Вызовы socket
- Вызов окна программного кода