Re: [xsl] Group and sort nodes by attribut in child node

Subject: Re: [xsl] Group and sort nodes by attribut in child node
From: Martin Honnen <Martin.Honnen@xxxxxx>
Date: Fri, 14 Oct 2011 16:29:31 +0200
Martin Honnen wrote:
Jens Burkhardt wrote:

The result should be like this:
A - 23.10.2010
X_Group
C - 23.10.2010
B - 24.12.2010
D - 25.10.2010
Y_Group
D - 25.12.2010
E - 26.12.2010

I want to group by the value of the group field in the column node and
everything should be sorted by start_date. The name of the group (e.g.
X_Group) should start a group-block, followed by the record nodes
which belong to the group value.
Another problem is that i donB4t know the group value in advance,
because they can be set to whatever the user want.

Do you use XSLT 2.0 or 1.0? And what about the record with keyword value "A" and the one with keyword value "D" where the group value is an empty string? Shouldn't they be in the same group?

Here is an XSLT 2.0 stylesheet that sorts first and the groups adjacent records in the sorted sequence:


<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
  xmlns:xs="http://www.w3.org/2001/XMLSchema";
  exclude-result-prefixes="xs"
  version="2.0">

<xsl:output method="text"/>

<xsl:template match="records">
<xsl:variable name="sorted" as="element(record)*">
<xsl:perform-sort select="record">
<xsl:sort select="xs:date(concat(substring(column[@field = 'Start_Date']/@value, 7), '-',
substring(column[@field = 'Start_Date']/@value, 4, 2), '-',
substring(column[@field = 'Start_Date']/@value, 1, 2)))"/>
</xsl:perform-sort>
</xsl:variable>
<xsl:for-each-group select="$sorted" group-adjacent="column[@field = 'Group']/@value">
<xsl:choose>
<xsl:when test="current-grouping-key()">
<xsl:value-of select="current-grouping-key()"/>
<xsl:text>&#10;</xsl:text>
<xsl:value-of select="current-group()/concat(' ', column[@field = 'keyword']/@value, ' - ', column[@field = 'Start_Date']/@value)"
separator="&#10;"/>
<xsl:text>&#10;</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="current-group()/concat(column[@field = 'keyword']/@value, ' - ', column[@field = 'Start_Date']/@value)"/>
<xsl:text>&#10;</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:template>


</xsl:stylesheet>

With that stylesheet Saxon 9.3 HE, when applying it to the input

<records>
<record>
   <column field="keyword" value="A"></column>
   <column field="Start_Date" value="23.12.2010"></column>
   <column field="Group" value=""></column>
</record>
<record>
   <column field="keyword" value="B"></column>
   <column field="Start_Date" value="24.12.2010"></column>
   <column field="Group" value="X_Group"></column>
</record>
<record>
   <column field="keyword" value="D"></column>
   <column field="Start_Date" value="25.12.2010"></column>
   <column field="Group" value=""></column>
</record>
<record>
   <column field="keyword" value="C"></column>
   <column field="Start_Date" value="23.12.2010"></column>
   <column field="Group" value="X_Group"></column>
</record>
<record>
   <column field="keyword" value="D"></column>
   <column field="Start_Date" value="25.12.2010"></column>
   <column field="Group" value="Y_Group"></column>
</record>
<record>
   <column field="keyword" value="E"></column>
   <column field="Start_Date" value="26.12.2010"></column>
   <column field="Group" value="Y_Group"></column>
</record>
</records>

outputs

A - 23.12.2010
X_Group
 C - 23.12.2010
 B - 24.12.2010
D - 25.12.2010
Y_Group
 D - 25.12.2010
 E - 26.12.2010


Does that solution meet your requirement?




--

	Martin Honnen --- MVP Data Platform Development
	http://msmvps.com/blogs/martin_honnen/

Current Thread