Выбрать главу

 <foo foo="4">

  <bar bar="5"/>

  <bar foo="6"/>

 </foo>

</foo>

Листинг 11.5. Преобразование

<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.&#xA;</xsclass="underline" text>

  </xsclass="underline" if>

  <!-- Рекурсивно обрабатываем дочерний элемент и атрибуты -->

  <xsclass="underline" apply-templates select="*|@*"/>

 </xsclass="underline" template>

</xsclass="underline" stylesheet>

Листинг 11.6. Выходящий документ

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 присваивается булевое значение результата сравнения.

Листинг 11.7. Вычисление булевого значения функции

<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"/>