<foo foo="4">
<bar bar="5"/>
<bar foo="6"/>
</foo>
</foo>
<xsclass="underline" stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- Выводим информацию в текстовом виде -->
<xsclass="underline" output method="text"/>
<!--
| Создаем ключ, отображающий узлы атрибутов и элементов
| в их локальные части имен.
+-->
<xsclass="underline" key name="node" match="*" use="local-name()"/>
<xsclass="underline" key name="node" match="@*" use="local-name()"/>
<xsclass="underline" template match="*|@*">
<xsclass="underline" variable name="name" select="local-name()"/>
<!--
| Если узел является первым узлом группы (первым встретившимся
| узлом документа с данным именем), выводим информацию о
| количестве узлов в группе (количество узлов с таким же именем).
+-->
<xsclass="underline" if test="generate-id(.) = generate-id(key('node', $name))">
<xsclass="underline" text>Node '</xsclass="underline" text>
<xsclass="underline" value-of select="local-name()"/>
<xsclass="underline" text>' found </xsclass="underline" text>
<xsclass="underline" value-of select="count(key('node', $name))"/>
<xsclass="underline" text> times.
</xsclass="underline" text>
</xsclass="underline" if>
<!-- Рекурсивно обрабатываем дочерний элемент и атрибуты -->
<xsclass="underline" apply-templates select="*|@*"/>
</xsclass="underline" template>
</xsclass="underline" stylesheet>
Node 'foo' found 5 times.
Node 'bar' found 7 times.
Именованный шаблон как функция
Сложно переоценить возможности механизмов расширений языка XSLT. Они позволяют сочетать простоту и гибкость обработки XML-документов при помощи элементов XSLT и выражений XPath. Практически любая функция, которая отсутствует в XSLT, может быть написана на подходящем языке программирования и подключена к процессору.
Но как уже отмечалось ранее, функции расширения ограничивают переносимость преобразований. Во-первых, функции расширения одного процессора совсем необязательно будут присутствовать в другом процессоре — скорее наоборот. Во-вторых, не приходится надеяться, что пользовательские модули, написанные на одном языке или с использованием одного интерфейса, смогут использоваться любым процессором. Поэтому часто перед разработчиком стоит проблема решить определенную задачу, используя только стандартные функции и элементы XSLT.
В этом разделе мы рассмотрим возможность использования именованных шаблонов в качестве функций, которые принимают на вход несколько параметров и возвращают некоторое вычисленное значение.
Использование именованных шаблонов как функций обуславливается следующими тезисами.
□ Именованный шаблон можно вызывать вне зависимости от того, какая часть документа обрабатывается в данный момент.
□ Именованному шаблону можно передавать параметры.
□ Результат выполнения именованного шаблона можно присваивать переменной.
Вызов именованного шаблона выполняется элементом xsclass="underline" call-template
, в атрибуте name
которого указывается имя вызываемого шаблона. Такой вызов не зависит от того, какая часть документа обрабатывается в данный момент и может производиться по необходимости.
Параметры именованному шаблону передаются точно так же, как и обычному — при помощи элементов xsclass="underline" with-param
, которые могут быть включены в вызывающий элемент xsclass="underline" call-template
. Примером вызова именованного шаблона с параметрами может быть конструкция вида
<xsclass="underline" call-template name="foo">
<xsclass="underline" with-param name="x" select="1"/>
<xsclass="underline" with-param name="y" select="2"/>
</xsclass="underline" call-template>
которая вызывает шаблон с именем foo
и передает ему параметр x
со значением, равным 1
и параметр y
со значением, равным 2
.
Вызов именованного шаблона может также производиться при инициализации переменной — внутри элемента xsclass="underline" variable. В этом случае с переменной связывается результирующий фрагмент дерева, возвращаемый именованным шаблоном.
В качестве примера приведем простой шаблон, который вычисляет квадрат переданного ему параметра x
:
<xsclass="underline" template name="sqr">
<xsclass="underline" param name="x"/>
<xsclass="underline" value-of select="$x * $x"/>
</xsclass="underline" template>
Для того чтобы присвоить переменной у
квадрат числа 6
мы можем записать следующее:
<xsclass="underline" variable name="y">
<xsclass="underline" call-template name="sqr">
<xsclass="underline" with-param name="x" select="6"/>
</xsclass="underline" call-template>
</xsclass="underline" variable>
Обратим внимание, что значение переменной y
будет иметь вовсе не численный тип. Несмотря на то, что элемент
<xsclass="underline" value-of select="$y"/>
выведет строку "36
", переменная у содержит не число, а дерево, и 36
лишь является результатом конвертации в строку при выполнении xsclass="underline" value-of
.
Для того чтобы присвоить переменной результат выполнения именованного шаблона в виде булевого значения, строки или числа, следует воспользоваться промежуточной переменной для явного преобразования типов.
После выполнения действий
<xsclass="underline" variable name="result">
<xsclass="underline" call-template name="sqr">
<xsclass="underline" with-param name="x" select="6"/>
</xsclass="underline" call-template>
</xsclass="underline" variable>
<xsclass="underline" variable name="sqr-string" select="string($result)"/>
<xsclass="underline" variable name="sqr-number" select="number($result)"/>
переменные sqr-string
и sqr-number
будут содержать строковое и численное значение результата вычисления соответственно.
Немного сложнее обстоит дело с булевым типом. При приведении дерева к булевому типу результатом всегда будет "истина", поэтому такое преобразование необходимо выполнить в два шага: сначала преобразовать дерево в число, только затем число в булевый тип.
В следующем преобразовании шаблон с именем less-than
сравнивает значения параметров x
и y
. Переменной less-than
присваивается булевое значение результата сравнения.
<xsclass="underline" stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsclass="underline" template match="/">
<xsclass="underline" variable name="result">
<xsclass="underline" call-template name="less-than">
<xsclass="underline" with-param name="x" select="2"/>