This conversion is :
<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 to 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>
creates the desired result :
<Field name="abc" displayName="aaa"/> <Field name="abc" displayName="aaa"/>
Explanation
Muenchian grouping using a composite key (in the name and displayName attributes) <.
The only template in the code matches any Field element that is second in the corresponding group. Then, the entire group is displayed inside the template body.
Muenchian grouping is an efficient way to group 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 to the provided XML document (shown above), the desired, correct result is again obtained :
<Field name="abc" displayName="aaa"/> <Field name="abc" displayName="aaa"/>
Explanation
source share