Алексей Валиков - Технология XSLT
Другой иллюстрацией этому же случаю использования переменной может быть следующая ситуация: в некоторых случаях выражения могут быть просты для вычисления, но слишком громоздки для записи. Гораздо элегантней один раз вычислить это громоздкое выражение, сохранить его в переменной и затем обращаться по короткому имени. Например, следующий элемент xsl:variable вычисляет и сохраняет в переменной gv длинную и громоздкую ссылку:
<xsl:variable name="gv"
select="concat('http://host.com:8080/GeoView/GeoView.jsp?',
'Language=en&',
'SearchText=Select&',
'SearchTarget=mainFrame&',
'SearchURL=http://host.com:8080/servlet/upload')"/>
После такого определения применение этой ссылки в преобразовании становится удобным и лаконичным:
<а href="{$gv}" target="_blank">Launch GeoBrowser</a>
Второй типовой случай использования переменных также заметно облегчает создание выходящего дерева, делая этот процесс гибким и легко конфигурируемым. Примером формирования HTML-документа при помощи такого подхода может быть следующий шаблон:
<xsl:template match="/">
<html>
<xsl:copy-of select="$head"/>
<xsl:copy-of select="$body"/>
</html>
</xsl:template>
Достоинство этого подхода в том, что переменные, содержащие фрагменты деревьев как бы становятся модулями, блоками, из которых в итоге собирается результирующий документ.
Более практичным применением возможности переменных содержать фрагменты деревьев является условное присвоение переменной значения. Представим себе следующий алгоритм:
если
условие1
то
присвоить переменной1 значение 1
иначе
присвоить переменной1 значение2
Для процедурного языка с изменяемыми переменными это не проблема. На Java такой код выглядел бы элементарно:
переменная1 = условие1 ? значение1 : значение2;
или чуть в более длинном варианте:
if (условие1)
переменная1 = значение1;
else
переменная1 = значение2;
Однако если бы в XSLT мы написали что-нибудь наподобие:
<xsl:choose>
<xsl:when test="условие1">
<xsl:variable name="переменная1" select="значение1"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="переменная1" select="значение2"/>
</xsl:otherwise>
</xsl:choose>
то требуемого результата все равно не достигли бы по той простой причине, что определенные нами переменные были бы доступны только в своей области видимости, которая заканчивается закрывающими тегами элементов xsl:when и xsl:otherwise. Правильный шаблон для решения этой задачи выглядит следующим образом:
<xsl:variable name="переменная1">
<xsl:choose>
<xsl:when test="условие1">
<xsl:copy-of select="значение1"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="значение2"/>
</xsl:otherwise>
</xsl:choose>
<xsl:variable>
Конечно, это не точно то же самое — на самом деле мы получаем не значение, а дерево, содержащее это значение, но для строковых и численных значений особой разницы нет: дерево будет вести себя точно так же, как число или строка. Для булевых значений и множеств узлов приходится изыскивать другие методы. Булевое значение можно выразить через условие, например:
<xsl:variable name="переменная 1"
select="(значение 1 and условие1) or (значение2 and not(условие2))"/>
Для множества узлов можно использовать предикаты и операции над множествами:
<xsl:variable name="переменная1"
select="значение1[условие1] | значение2[not(условие2)]"/>
Заметим, что шаблон, содержащийся в элементе xsl:variable, может включать в себя такие элементы, как xsl:call-template, xsl:apply-templates и так далее. То есть переменной можно присвоить результат выполнения одного или нескольких шаблонов.
Использование внешних документов в преобразовании, как правило, сопровождается громоздкими выражениями вида:
document('http://www.xmlhost.com/docs/а.xml')/page/request/param
и так далее.
Для того чтобы при обращении к внешнему документу не использовать каждый раз функцию document, можно объявить переменную, которая будет содержать корневой узел этого документа, например:
<xsl:variable
name="a.xml"
select="document('http://www.xmlhost.com/docs/a.xml')"/>
После этого к документу http://www.xmlhost.com/docs/a.xml можно обращаться посредством переменной с именем a.xml, например:
<xsl:value-of select="$a.xml/page/request/param"/>
Параметры
Параметры в XSLT практически полностью идентичны переменным. Они точно так же связывают с объектом имя, посредством которого в дальнейшем можно к этому объекту обращаться. Главным различием является то, что значение, данное параметру при инициализации, является всего лишь значением по умолчанию, которое может быть переопределено при вызове.
До сих пор мы говорили о шаблонах, как о правилах, часто используя эти слова как синонимы. Попробуем теперь немного сменить угол зрения и представить их как функции, каждая из которых преобразует некоторый узел и возвращает фрагмент дерева в качестве результата. С этой точки зрения параметры шаблонов являются ни чем иным, как аргументами этих функций.
Работа с параметрами обеспечивается двумя элементами — xsl:param, который объявляет в шаблоне новый параметр и xsl:with-param, который указывает значение параметра при вызове шаблона.
Элемент xsl:param
Синтаксически этот элемент задается как:
<xsl:param
name="имя"
select="выражение">
<!-- Содержимое: шаблон -->
</xsl:param>
Элемент xsl:template, задающий в преобразовании шаблонное правило, может включать несколько элементов xsl:param, которые и будут определять параметры этого шаблона. Кроме этого, xsl:param может указываться в виде элемента верхнего уровня — в этом случае он будет определять глобальный параметр.
Элемент xsl:param объявляет параметр с именем, которое задается обязательным атрибутом name. Имя параметра может иметь расширенную форму, например "user:param", но чтобы не возиться с пространствами имен, на практике имена всегда дают простые — типа "i" или "myParam".
Параметру может быть присвоено значение по умолчанию — то есть значение, которое будет использоваться в случае, если параметра с таким именем шаблону передано не было. Значение по умолчанию вычисляется следующим образом:
□ если в элементе xsl:param определен атрибут select, то значением по умолчанию будет результат вычисления выражения, указанного в этом атрибуте;
□ если атрибут select не определен, но сам элемент xsl:param имеет дочерние узлы, то значением определяемого параметра по умолчанию будет фрагмент дерева, полученного в результате выполнения содержимого xsl:param;
□ если атрибут select не определен и при этом сам элемент xsl:param пуст, то значением параметра по умолчанию будет пустая строка.
ПримерыЭлемент
<xsl:param name="x" select="2 * 2"/>
создаст параметр, значением которого по умолчанию будет 4. Точно такой же эффект будет иметь элемент
<xsl:param name="x" select="2 * 2">
<xsl:value-of select="5 * 5/>
</xsl:param>
Его содержимое не будет приниматься в расчет, поскольку в xsl:param присутствует атрибут select. Если же убрать атрибут select:
<xsl:param name="x">
<xsl:value-of select="5 * 5/>
</xsl:param>
то значение параметра x по умолчанию действительно будет результатом вычисления его содержимого. Однако, вопреки довольно здравому разумению, этим значением не будет число 25 и даже не строка "25" и тем более не множество, состоящее из текстового узла со значением 25. Значением параметра x по умолчанию будет результирующий фрагмент дерева, корень которого будет иметь единственный текстовый узел со значением "25" (рис. 5.3).
Рис. 5.3. Фрагмент дерева, который будет значением параметра x по умолчанию
Не стоит пугаться такой структуры в качестве значения параметра. То, что параметр x вдруг будет содержать дерево, ничуть не ограничивает его использование, ведь дерево при потребности может быть приведено к числу или к строке; к множеству узлов же не может быть приведен ни один тип данных.