How to display duplicate elements using XSLT?

I have an xml that looks something like this:

<Root> <Fields> <Field name="abc" displayName="aaa" /> <Field name="pqr" displayName="ppp" /> <Field name="abc" displayName="aaa" /> <Field name="xyz" displayName="zzz" /> </Fields> </Root> 

I want the output to contain only those elements that have a repeating name-displayName combination, if there is -

 <Root> <Fields> <Field name="abc" displayName="aaa" /> <Field name="abc" displayName="aaa" /> </Fields> </Root> 

How to do it with XSLT?

+6
source share
2 answers

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

+7
source

To find duplicates, you need to iterate through the Field elements and for each of them, find the set of Field elements in the entire document that have the corresponding values ​​for the name and displayName attributes. If the collection contains more than one element, you add this element to the output file.

Here is an example of a template that accomplishes this:

 <xsl:template match="Field"> <xsl:variable name="fieldName" select="@name" /> <xsl:variable name="fieldDisplayName" select="@displayName" /> <xsl:if test="count(//Field[@name=$fieldName and @displayName=$fieldDisplayName]) > 1"> <xsl:copy-of select="."/> </xsl:if> </xsl:template> 

Executing this template (wrapped in the appropriate XSLT file) in your sample data gives the following result:

 <?xml version="1.0" encoding="utf-8"?> <Root> <Fields> <Field name="abc" displayName="aaa" /> <Field name="abc" displayName="aaa" /> </Fields> </Root> 
+1
source

Source: https://habr.com/ru/post/887617/


All Articles