Группировка
Xpoint.ru » База знаний » XML » The Extensible Stylesheet Language Transformations (XSLT) » Готовые решения » Группировка
Оглавление
Постановка задачи
Дано
<?xml version="1.0"?> <list> <item id="aa" group="x"/> <item id="bb" group="y"/> <item id="ab" group="x"/> <item id="ba" group="z"/> <item id="cc" group="y"/> <item id="ac" group="y"/> <item id="ca" group="x"/> <item id="dc" group="x"/> <item id="ad" group="z"/> <!-- ... --> </list>
Требуется получить
<?xml version="1.0"?> <group-list> <group name="x"> <item name="aa"/> <item name="ab"/> <item name="ca"/> <item name="dc"/> </group> <group name="y"> <item name="bb"/> <item name="cc"/> <item name="ac"/> </group> <group name="z"> <item name="ba"/> <item name="ad"/> </group> </group-list>
Т.е. нужно сгруппировать узлы по некоторому признаку.
Стандартное решение: группировка Мюнха.
Метод Мюнха основан на том факте, что при передаче функции generate-id множества узлов, она возвращает id первого из них. Значит, если она вернула id текущего узла, то он — первый в этом множестве:
<?xml version="1.0"?> <xsl:stylesheet version="1.0" exclude-result-prefixes="xsl" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > <xsl:output method="xml" indent="yes"/> <xsl:key name="group" match="item" use="@group"/> <xsl:template match="list"> <group-list> <xsl:apply-templates select="item[generate-id(.) = generate-id(key('group',@group))]" /> </group-list> </xsl:template> <xsl:template match="item"> <group name="{@group}"> <xsl:for-each select="key('group',@group)"> <item name="{@id}"/> </xsl:for-each> </group> </xsl:template> </xsl:stylesheet>
Решение в XSLT 2.0
Задача столь распространена, что в XSLT 2.0 для этих целей был введен специальный элемент xsl:for-each-group. С его использованием задача становитя совсем простой:
<?xml version="1.0"?>
<xsl:stylesheet version="2.0"
exclude-result-prefixes="xsl"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="list">
<group-list>
<xsl:for-each-group select="item" group-by="@group">
<group name="{@group}">
<xsl:for-each select="current-group()">
<item name='{@id}'/>
</xsl:for-each>
</group>
</xsl:for-each-group>
</group-list>
</xsl:template>
</xsl:stylesheet>
Вообще говоря, возможности xsl:for-each-group гораздо шире, чем позволяет видеть показанный здесь пример. Полностью они описаны в разделе «Grouping» спецификации.
![[logo]](/site/images/logo.jpg)