Следующая таблица стилей показывает общий подход к группированию на нескольких уровнях:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="byRegion" match="Row" use="@region" />
<xsl:key name="byRegionState"
match="Row" use="concat(@region, '|', @state)" />
<xsl:key name="byRegionStateDept"
match="Row" use="concat(@region, '|', @state, '|', @dept)" />
<xsl:template
match="Row[generate-id() = generate-id(key('byRegion', @region)[1])]">
<region name="{@region}">
<xsl:apply-templates
select="key('byRegion', @region)
[generate-id() =
generate-id(key('byRegionState',
concat(@region, '|', @state))[1])]"
mode="states" />
</region>
</xsl:template>
<xsl:template match="Row" mode="states">
<state name="{@state}">
<xsl:apply-templates
select="key('byRegionState', concat(@region, '|', @state))
[generate-id() =
generate-id(key('byRegionStateDept',
concat(@region, '|', @state, '|', @dept))[1])]"
mode="dept" />
</state>
</xsl:template>
<xsl:template match="Row" mode="dept">
<dept><xsl:value-of select="@dept" /></dept>
</xsl:template>
</xsl:stylesheet>
Он выдаст следующий вывод на ваш вход:
<region name="East">
<state name="NY">
<dept>HR</dept>
<dept>SD</dept>
<dept>MM</dept>
</state>
<state name="NJ">
<dept>HR</dept>
<dept>SD</dept>
</state>
</region>
<region name="West">
<state name="CO">
<dept>SD</dept>
<dept>MM</dept>
</state>
</region>