This transformation:
<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>
when applied on the provided XML document:
<Root>
<Fields>
<Field name="abc" displayName="aaa" />
<Field name="pqr" displayName="ppp" />
<Field name="abc" displayName="aaa" />
<Field name="xyz" displayName="zzz" />
</Fields>
</Root>
produces the wanted result:
<Field name="abc" displayName="aaa"/>
<Field name="abc" displayName="aaa"/>
Explanation:
Muenchian grouping using composite key (on the name
and displayName
attributes).
The only template in the code matches any Field
element that is the second in its corresponding group. Then, inside the body of the template, the whole group is output.
Muenchian grouping is the efficient way to do grouping in XSLT 1.0. Keys are used for efficiency.
See also my answer to this question.
II. XSLT 2.0 solution:
<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>
When this transformation is applied on the provided XML document (shown above), again the wanted, correct result is produced:
<Field name="abc" displayName="aaa"/>
<Field name="abc" displayName="aaa"/>
Explanation:
Use of <xsl:for-each-group>
Use of the current-group()
function.