Это преобразование :
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kFieldByName" match="Field"
use="concat(@name, '+', @displayName)"/>
<xsl:template match=
"Field[generate-id()
=
generate-id(key('kFieldByName',
concat(@name, '+', @displayName)
)[2])
]
">
<xsl:copy-of select=
"key('kFieldByName',concat(@name, '+', @displayName))"/>
</xsl:template>
</xsl:stylesheet>
при применении к предоставленному документу XML :
<Root>
<Fields>
<Field name="abc" displayName="aaa" />
<Field name="pqr" displayName="ppp" />
<Field name="abc" displayName="aaa" />
<Field name="xyz" displayName="zzz" />
</Fields>
</Root>
дает желаемый результат :
<Field name="abc" displayName="aaa"/>
<Field name="abc" displayName="aaa"/>
Объяснение
мюнхенская группировка с использованием составного ключа (для атрибутов name
и displayName
).
Единственный шаблон в коде соответствует любому элементу Field
, который является вторым в соответствующей группе. Затем внутри тела шаблона выводится вся группа.
Группировка по Мюнхену - это эффективный способ группировки в XSLT 1.0. Ключи используются для эффективности.
См. Также мой ответ на этот вопрос .
II. Решение XSLT 2.0 :
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:for-each-group select="/*/*/Field"
group-by="concat(@name, '+', @displayName)">
<xsl:sequence select="current-group()[current-group()[2]]"/>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
Когда это преобразование применяется к предоставленному XML-документу (показанному выше), снова получается требуемый, правильный результат :
<Field name="abc" displayName="aaa"/>
<Field name="abc" displayName="aaa"/>
Объяснение
Использование <xsl:for-each-group>
Использование функции current-group()
.