Решение XSLT-1.0 заключается в следующем. Он использует Muenchian Grouping в качестве метода для получения уникальных значений страны.
EDIT:
Чтобы убедиться, что имена элементов являются действительными QNames, я добавил выражение translate(...)
, которое преобразует все пробелы в названии соответствующего города или страны в подчеркивание.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="countries" match="A" use="country" />
<xsl:template match="/*">
<xsl:copy>
<xsl:apply-templates select="node()|@*" />
</xsl:copy>
</xsl:template>
<xsl:template match="text()" />
<xsl:template match="A[generate-id(.) = generate-id(key('countries',country)[1])]">
<xsl:element name="{translate(country,' ','_')}">
<xsl:for-each select="key('countries',country)">
<xsl:element name="{translate(city,' ','_')}">
<xsl:copy-of select="score" />
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Решение XSLT-2.0 проще, поскольку оно может использовать xsl:for-each-group
:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/*">
<xsl:copy>
<xsl:for-each-group select="A" group-by="country">
<xsl:element name="{translate(current-grouping-key(),' ','_')}">
<xsl:for-each select="current-group()">
<xsl:element name="{translate(city,' ','_')}">
<xsl:copy-of select="score" />
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Вывод обоих подходов одинаков:
<?xml version="1.0"?>
<root>
<Italy>
<Rome>
<score>13</score>
</Rome>
<Florence>
<score>14</score>
</Florence>
</Italy>
<France>
<Paris>
<score>20</score>
</Paris>
</France>
</root>