Ниже представлены решения XSLT 1.0 и XSLT 2.0. Оба решения используют различный подход, как справедливо указано @Tim C. в комментарии.
XSLT 1.0
В случае XSLT 1.0 используется muenchian группировка . <xsl:key>
необходимо определить для группировки элементов. В этом случае <plan_id>
- это ключ, по которому будет выполняться группировка.
<xsl:key name="plan" match="package" use="package_plan/plan_id" />
Элементы package
сопоставляются соответствующим образом, и сгруппированные данные копируются в вывод.
<xsl:template match="package[generate-id() = generate-id(key('plan', package_plan/plan_id)[1])]">
<xsl:copy>
<xsl:variable name="varPlan" select="key('plan', package_plan/plan_id)" />
<xsl:apply-templates select="$varPlan[1]/package_plan/plan_id" />
<xsl:apply-templates select="$varPlan[1]/package_plan/plan_name" />
<channels>
<xsl:for-each select="$varPlan">
<xsl:apply-templates select="rate_channel" />
</xsl:for-each>
</channels>
</xsl:copy>
</xsl:template>
Остальные элементы <package>
удалены.
<xsl:template match="package" />
XSLT 2.0
В XSLT 2.0 функция <xsl-for-each-group>
доступна специально для группировки элементов. В этом случае, используя эту функцию и функцию current-group()
, можно добиться группировки.
<xsl:template match="subscriptions">
<xsl:copy>
<xsl:for-each-group select="package" group-by="package_plan/plan_id">
<package>
<xsl:apply-templates select="current-group()[1]/package_plan/plan_id" />
<xsl:apply-templates select="current-group()[1]/package_plan/plan_name" />
<channels>
<xsl:for-each select="current-group()">
<xsl:apply-templates select="rate_channel" />
</xsl:for-each>
</channels>
</package>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
В обоих вышеупомянутых случаях следует использовать шаблон identity transform
для копирования данных как есть.
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()" />
</xsl:copy>
</xsl:template>