Книга: Технология XSLT

Группировка

Группировка

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

Листинг 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 — множество узлов этой группы.

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

Листинг 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.

Оглавление книги


Генерация: 0.040. Запросов К БД/Cache: 0 / 0
поделиться
Вверх Вниз