XSLT 2.0の場合は、ネストされたものを使用できます<xsl:for-each-group>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<Groups>
<xsl:for-each-group select="/Groups/GroupData" group-by="@ID">
<xsl:for-each-group select="current-group()" group-by="if(@Key) then @Key else 'no key'">
<GroupData>
<!-- Copy attributes off the *first* GroupData element in the group -->
<xsl:copy-of select="current-group()[1]/@*"/>
<!-- Copy ItemData children from *all* GroupData elements in the group -->
<xsl:copy-of select="current-group()/ItemData" />
</GroupData>
</xsl:for-each-group>
</xsl:for-each-group>
</Groups>
</xsl:template>
</xsl:stylesheet>
(入力ファイルにルート要素が<Groups>
あり、名前空間を使用していないと想定しています)。
XSLT 1.0の場合は、MuenchianGroupingを使用する必要があります。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="group-data" match="GroupData" use="concat(@ID, '___', @Key)" />
<xsl:template match="/">
<Groups>
<!--
Iterate over a node set containing just one GroupData element for
each combination of ID and Key
-->
<xsl:for-each select="/Groups/GroupData[count( . | key('group-data', concat(@ID, '___', @Key))[1]) = 1]">
<GroupData>
<!-- Copy attributes from the "prototype" GroupData -->
<xsl:copy-of select="@*"/>
<!--
Copy ItemData children from *all* GroupData elements with matching
ID/Key
-->
<xsl:copy-of select="key('group-data', concat(@ID, '___', @Key))/ItemData" />
</GroupData>
</xsl:for-each>
</Groups>
</xsl:template>
</xsl:stylesheet>
key
ここでは、の合成値を作成することにより、ID属性とKey属性の両方に基づいて単一のグループ化パスを実行しています{ID}___{Key}
。