Технология XSLT — страница 53 из 66

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

Инициатива EXSLT была порождена естественным желанием разработчиков иметь в своих XSLT-преобразованиях стандартные расширения и не дублировать усилия по решению общих проблем. В рамках EXSLT создаются стандартные библиотеки расширений XSLT для различных процессоров. Кроме того, EXSLT активно поддерживается многими разработчиками XSLT-процессоров с тем, чтобы обеспечить переносимость преобразований, использующих EXSLT-расширения.

Для конечного пользователя EXSLT — это множество библиотек расширений, которые можно загрузить с сайта http://www.exslt.org. Помимо этого, EXSLT-расширения уже являются встроенными для некоторых процессоров. Например, в процессоре Saxon реализовано большинство элементов и функций расширения EXSLT.

На данном этапе разработанные в рамках EXSLT библиотеки включают в себя следующие модули.

Common
— общие функции и элементы расширения. Включает функции
exslt:node-set
и
exslt:object-type
и элемент
exslt:document
.

Math
— математические функции.

Sets
— функции для работы с множествами узлов (как-то: пересечение, разность и так далее).

Functions
— элементы для определения пользовательских функций.

Dates and Times
— элементы и функции для работы с временными параметрами.

Strings
— модуль для работы со строками.

Regular Expressions
— функции для работы с регулярными выражениями.

EXSLT покрывает большинство стандартных задач расширений — поэтому, прежде, чем браться за разработку собственных модулей расширения, следует проверить — нет ли уже реализованных аналогов. Кроме того, библиотеки EXSLT могут послужить хорошим примером программирования расширений.

Глава 11Готовые решения

Группировка

Мы уже рассматривали задачу группировки, когда разбирали устройство и функционирование ключей — это была та самая задача, в которой из документа вида.

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

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

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

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

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. Группирующее преобразование

 version="1.0"

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



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



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

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

Функции

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

 ...

то обрабатываться им будут все элементы, локальные части имен которых начинаются на

"чеб"
(например,
"чебуреки"
,
"Чебоксары"
,
"чебурашка"
).

Следующее преобразование демонстрирует, как при помощи функции

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

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

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