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

Использование переменных

Использование переменных

Как правило, первой реакцией на известие о том, что переменные в XSLT нельзя изменять является реплика: "Да зачем они вообще тогда нужны?!".

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

? Переменные могут содержать значения выражений, которые много раз используются в преобразовании. Это избавит процессор от необходимости пересчитывать выражение каждый раз по-новому.

? Переменной может присваиваться результат преобразования, что позволяет манипулировать уже сгенерированными частями документа.

? Переменные могут использоваться для более прозрачного доступа к внешним документам.

Примеры

Первый случай использования совершенно очевиден: если в преобразовании многократно используется какое-либо сложное для вычисления или просто громоздкое для записи выражение, переменная может служить для сохранения единожды вычисленного результата. Например, если мы много раз обращаемся ко множеству ссылок данного документа посредством выражения вида:

//a[@href]

гораздо удобней и экономней с точки зрения вычислительных ресурсов объявить переменную вида

<xsl:variable name="links" select="//a[@href]"/>

и использовать ее в преобразовании как $a. Фильтрующие выражения языка XPath (продукция FilterExpr) позволяют затем обращаться к узлам выбранного множества так же, как если бы мы работали с изначальным выражением. Например, $a[1] будет эквивалентно //a[@href][1], a $a/@href — выражению //a[@href]/@href. При этом при обращении к $a процессор не будет заново искать все элементы a с атрибутом href, что, по всей вероятности, положительно скажется на производительности.

Другой иллюстрацией этому же случаю использования переменной может быть следующая ситуация: в некоторых случаях выражения могут быть просты для вычисления, но слишком громоздки для записи. Гораздо элегантней один раз вычислить это громоздкое выражение, сохранить его в переменной и затем обращаться по короткому имени. Например, следующий элемент xsl:variable вычисляет и сохраняет в переменной gv длинную и громоздкую ссылку:

<xsl:variable name="gv"
 select="concat('http://host.com:8080/GeoView/GeoView.jsp?',
 'Language=en&amp;',
 'SearchText=Select&amp;',
 'SearchTarget=mainFrame&amp;',
 '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"/>

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


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