XSLT - Стивен Холзнер
Шрифт:
Интервал:
Закладка:
<xsl:call-template name="localize">
<xsl:with-param name="language" select="'fr'"/>
</xsl:call-template>
</H1>
<TABLE BORDER="2">
<TR>
<TD>Name</TD>
<TD>Mass</TD>
<TD>Radius</TD>
<TD>Day</TD>
</TR>
<xsl:apply-templates/>
</TABLE>
</BODY>
</HTML>
</xsl:template>
<xsl:template name="localize">
<xsl:param name="language"/>
<xsl:if test="$language='en'">
<xsl:text>Planets</xsl:text>
</xsl:if>
<xsl:if test="$language='de'">
<xsl:text>Planeten</xsl:text>
</xsl:if>
<xsl:if test="$language='fr'">
<xsl:text>Planètes</xsl:text>
</xsl:if>
</xsl:template>
.
.
.
Вот результирующий локализованный документ:
<HTML>
<HEAD>
<TITLE>Planètes</TITLE>
</HEAD>
<BODY>
<H1>Planètes</H1>
<TABLE BORDER="2">
<TR>
<TD>Name</TD>
<TD>Mass</TD>
<TD>Radius</TD>
<TD>Day</TD>
</TR>
.
.
.
Этот документ показан на рис. 9.3.
Рис. 9.3. Вызов именованного шаблона с параметрами для установки языков
Вызов шаблона во многом похож на вызов функции, что обсуждалось в главе 8, и способность передавать данные через параметры усиливает сходство. Но в отсутствие оператора присваивания, как в языках программирования, кажется, что нельзя присвоить переменной значение, возвращаемое именованным шаблоном, впрочем, поразмыслив, это можно сделать. С шаблонами можно и еще в одном случае поступить так же, как с функциями, — осуществить рекурсивный вызов.
Рекурсивный вызов шаблонов
Эта тема предназначена, главным образом, для программистов, поскольку здесь я буду пользоваться 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, в котором разрешены использованные здесь фрагменты результирующего дерева.
Шаблон: значение по умолчанию
Как я говорил ранее, в случае задания параметру значения при объявлении, оно может быть перекрыто, если вы зададите другое значение в элементе <xsl:with-param>. Но если другого значения не указывать, исходное значение выступит в роли значения по умолчанию.
Следующий пример видоизменяет рассмотренный ранее пример «COLORS». Шаблон имеет параметр COLOR, но я могу вызвать шаблон, не устанавливая COLOR в какое-либо определенное значение:
<xsl:template match="PLANET">
<xsl:if test="NAME='Mercury'">
<xsl:call-template name="COLORS">
<xsl:with-param name="COLOR" select="'RED'"/>
</xsl:call-template>
</xsl:if>
<xsl:if test="NAME='Venus'">
<xsl:call-template name="COLORS">
<xsl:with-param name="COLOR" select="'GREEN'"/>
</xsl:call-template>
</xsl:if>
<xsl:if test="NAME='Earth'">
<xsl:call-template name="COLORS">
</xsl:call-template>
</xsl:if>
</xsl:template>
В этом случае параметр COLOR принимает значение по умолчанию«blue» (голубой), заданное в элементе <xsl:param> в шаблоне «COLORS»:
<xsl:template match="PLANET">
<xsl:if test="NAME='Mercury'">
<xsl:call-template name="COLORS">
<xsl:with-param name="COLOR" select="'RED'"/>
</xsl:call-template>
</xsl:if>
<xsl:if test="NAME='Venus'">
<xsl:call-template name="COLORS">
<xsl:with-param name="COLOR" select="'GREEN'"/>
</xsl:call-template>
</xsl:if>
<xsl:if test="NAME='Earth'">
<xsl:call-template name="COLORS">
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="COLORS">
<xsl:param name="COLOR" select="'blue'"/>
<TR>
<TD>
<FONT COLOR="{$COLOR}"><xsl:value-of select="NAME"/></FONT>
</TD>
<TD>
<FONT COLOR="{$COLOR}"><xsl:apply-templates select="MASS"/></FONT>
</TD>
<TD>
<FONT COLOR="{$COLOR}"><xsl:apply-templates select="RADIUS"/></FONT>
</TD>
<TD>
<FONT COLOR="{$COLOR}"><xsl:apply-templates select="DAY"/></FONT>
</TD>
</TR>
</xsl:template>
Как задавать значения шаблона в командной строке
Кроме возможностей, предоставляемых элементами <xsl:param> и <xsl:with-param>, значение параметров таблицы стилей во многих процессорах XSLT можно также задавать в командной строке. Способ зависит от конкретного процессора.