tags:

views:

154

answers:

2

Hi All, I have a xml that has so many elements and most of that contain attributes.. for some of the attributes values are same so I need to group them and generate diff xml. I/p Ex:

<TestNode>
 <ABC1 value="10.7" format="$" />
 <ABC2 value="10.5" format="$" />
 <ABC3 value="20" format="Rs" />
 <ABC4 value="50" format="Rs" />
 <ABC5 value="10.5" format="$" />
</TestNode>

I need to group the rows by format. Note: Format is not fixed... it may grow ... *O/P Ex:* is it possible to get ? Thanks in advance...

+2  A: 

In XSLT 2.0 you should be able to do it with <xsl:for-each-group>, current-grouping-key() and current-group()

Example:

<xsl:for-each-group 
    select="TestNode/*"
    group-by="@format"
>
    <group format="{current-grouping-key()}">
        <xsl:for-each select="current-group()">
            <xsl:copy-of select="."/>
        </xsl:for-each>
    </group>
</xsl:for-each-group>

See: http://www.w3.org/TR/xslt20/#grouping

Roland Bouman
The attribute on xsl:for-each-group is called 'group-by' not 'groupby'.And why that for-each to copy each item in the group, why not simply <xsl:copy-of select="current-group()"/> instead of the for-each?
Martin Honnen
Martin, thanks for pointing out the typo in group by. I hope the link to the spec I provided wasn't wasted on all who copied my suggestion verbatim. As for the `for-each`, the idea was to suggest how to access the individual items in the group. And indeed, if all you wanted to do was copy those items, then yes, indeed you could just use a single copy-by for the lot.
Roland Bouman
+3  A: 

In XSLT 1.0 you would use Muenchian grouping.

Define a key "format", from which we can easily select all elements given a format name. Than apply Muenchian grouping to find the unique formats in the input.

Then it gets simple. The "*" template will be applied once per format, and uses the key() to fetch all entries for that format.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;

    <xsl:output method="xml" indent="yes" />

    <xsl:key name="format" match="TestNode/*" use="@format" />

    <xsl:template match="TestNode">
        <body>
            <xsl:apply-templates select="*[generate-id(.)=generate-id(key('format',@format)[1])]"/>
        </body>
    </xsl:template>

    <xsl:template match="*">
        <format format="{@format}">
          <xsl:copy-of select="key('format', @format)" />
        </format>
    </xsl:template>

</xsl:stylesheet>
Lachlan Roche
Excellent suggestion!
Roland Bouman