Категории
Самые читаемые

Читаем без скачивания Технология XSLT - Алексей Валиков

Читать онлайн Технология XSLT - Алексей Валиков

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 98 99 100 101 102 103 104 105 106 ... 115
Перейти на страницу:

<items>

 <item source="a" name="A"/>

 <item source="b" name="B"/>

 <item source="a" name="C"/>

 <item source="c" name="D"/>

 <item source="b" name="E"/>

 <item source="b" name="F"/>

 <item source="c" name="G"/>

 <item source="a" name="H"/>

</items>

нужно было получить документ вида.

Листинг 11.2. Требуемый результат

<sources>

 <source name="а">

  <item source="a" name="A"/>

  <item source="a" name="C"/>

  <item source="a" name="H"/>

 </source>

 <source name="b">

  <item source="b" name="B"/>

  <item source="b" name="E"/>

  <item source="b" name="F"/>

 </source>

 <source name="c">

  <item source="c" name="D"/>

  <item source="c" name="G"/>

 </source>

</sources>

Легко понять, почему такая задача называется задачей группировки: требуется сгруппировать элементы item по значениям одного из своих атрибутов.

Напомним вкратце решение, которое было тогда предложено. При обработке первого объекта каждой группы мы создавали элемент source, в который включали все элементы item, принадлежащие этой группе. Для определения первого элемента мы использовали выражение

preceding-sibling::item[@source=current()/@source]

которое возвращало непустое множество только тогда, когда элемент не был первым в группе.

В этом разделе мы приведем гораздо более эффективное и остроумное решение задачи группировки, впервые предложенное Стивом Мюнхом (Steve Muench), техническим гуру из Oracle Corporation. Оно основывается на двух посылках.

□ Мы можем выбрать множество узлов по их свойствам при помощи ключей.

□ Мы можем установить, является ли узел первым узлом множества в порядке просмотра документа при помощи функции generate-id.

С первым пунктом все, пожалуй, ясно — выбор множества узлов по определенному критерию — это самое прямое предназначение ключей. Второй же пункт оставляет легкое недоумение: функция generate-id вроде бы предназначена только для генерации уникальных значений.

Для того чтобы развеять все сомнения, напомним, как ведет себя эта функция, если аргументом является множество узлов. В этом случае generate-id возвращает уникальный идентификатор первого в порядке просмотра документа узла переданного ей множества. Значит для того, чтобы проверить, является ли некий узел первым узлом группы, достаточно сравнить его уникальный идентификатор со значением выражения generate-id($group), где $group — множество узлов этой группы.

С учетом приведенных выше возможностей группирующее преобразование переписывается удивительно элегантным образом.

Листинг 11.3. Группирующее преобразование

<xsl:stylesheet

 version="1.0"

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 <xsl:key name="src" match="item" use="@source"/>

 <xsl:template match="items">

  <sources>

   <xsl:apply-templates

    select="item[generate-id(.)=generate-id(key('src', @source))]"/>

  </sources>

 </xsl:template>

 <xsl:template match="item">

  <source name="{@source}">

   <xsl:copy-of select="key('src', @source)"/>

  </source>

 </xsl:template>

</xsl:stylesheet>

Результат выполнения этого преобразования уже был приведен в листинге 11.2.

Перечисление узлов

Функции name и local-name предоставляют возможности для работы с документом, имена элементов и атрибутов в котором заранее неизвестны. Например, если шаблон определен как:

<xsl:template match="*[starts-with(local-name(), 'чеб')]">

 ...

</xsl:template>

то обрабатываться им будут все элементы, локальные части имен которых начинаются на "чеб" (например, "чебуреки", "Чебоксары", "чебурашка").

Следующее преобразование демонстрирует, как при помощи функции local-name и ключей сосчитать количество элементов и атрибутов документа с различными именами.

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

<foo bar="1">

 <bar foo="2"/>

 <bar bar="3"/>

 <foo foo="4">

  <bar bar="5"/>

  <bar foo="6"/>

 </foo>

</foo>

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

<xsl:stylesheet

 version="1.0"

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 <!-- Выводим информацию в текстовом виде -->

 <xsl:output method="text"/>

 <!--

  | Создаем ключ, отображающий узлы атрибутов и элементов

  | в их локальные части имен.

  +-->

 <xsl:key name="node" match="*" use="local-name()"/>

 <xsl:key name="node" match="@*" use="local-name()"/>

 <xsl:template match="*|@*">

  <xsl:variable name="name" select="local-name()"/>

  <!--

   | Если узел является первым узлом группы (первым встретившимся

   | узлом документа с данным именем), выводим информацию о

   | количестве узлов в группе (количество узлов с таким же именем).

   +-->

  <xsl:if test="generate-id(.) = generate-id(key('node', $name))">

   <xsl:text>Node '</xsl:text>

   <xsl:value-of select="local-name()"/>

   <xsl:text>' found </xsl:text>

   <xsl:value-of select="count(key('node', $name))"/>

   <xsl:text> times.&#xA;</xsl:text>

  </xsl:if>

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

  <xsl:apply-templates select="*|@*"/>

 </xsl:template>

</xsl:stylesheet>

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

Node 'foo' found 5 times.

Node 'bar' found 7 times.

Именованный шаблон как функция

Сложно переоценить возможности механизмов расширений языка XSLT. Они позволяют сочетать простоту и гибкость обработки XML-документов при помощи элементов XSLT и выражений XPath. Практически любая функция, которая отсутствует в XSLT, может быть написана на подходящем языке программирования и подключена к процессору.

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

В этом разделе мы рассмотрим возможность использования именованных шаблонов в качестве функций, которые принимают на вход несколько параметров и возвращают некоторое вычисленное значение.

Использование именованных шаблонов как функций обуславливается следующими тезисами.

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

□ Именованному шаблону можно передавать параметры.

□ Результат выполнения именованного шаблона можно присваивать переменной.

Вызов именованного шаблона выполняется элементом xsl:call-template, в атрибуте name которого указывается имя вызываемого шаблона. Такой вызов не зависит от того, какая часть документа обрабатывается в данный момент и может производиться по необходимости.

Параметры именованному шаблону передаются точно так же, как и обычному — при помощи элементов xsl:with-param, которые могут быть включены в вызывающий элемент xsl:call-template. Примером вызова именованного шаблона с параметрами может быть конструкция вида

<xsl:call-template name="foo">

 <xsl:with-param name="x" select="1"/>

 <xsl:with-param name="y" select="2"/>

</xsl:call-template>

которая вызывает шаблон с именем foo и передает ему параметр x со значением, равным 1 и параметр y со значением, равным 2.

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

Пример

В качестве примера приведем простой шаблон, который вычисляет квадрат переданного ему параметра x:

<xsl:template name="sqr">

 <xsl:param name="x"/>

 <xsl:value-of select="$x * $x"/>

</xsl:template>

Для того чтобы присвоить переменной у квадрат числа 6 мы можем записать следующее:

<xsl:variable name="y">

 <xsl:call-template name="sqr">

1 ... 98 99 100 101 102 103 104 105 106 ... 115
Перейти на страницу:
На этой странице вы можете бесплатно скачать Технология XSLT - Алексей Валиков торрент бесплатно.
Комментарии