</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()'/>

Вы читаете Технология XSLT
Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату