Для конечного пользователя 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 Входящий документ
<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
— множество узлов этой группы.
С учетом приведенных выше возможностей группирующее преобразование переписывается удивительно элегантным образом.