This is the mail archive of the
xsl-list@mulberrytech.com
mailing list .
Re: Grouping and Sorting on value inside group
- From: Jeni Tennison <jeni at jenitennison dot com>
- To: "Hunsberger, Peter" <Peter dot Hunsberger at stjude dot org>
- Cc: "'xsl-list at lists dot mulberrytech dot com'" <xsl-list at lists dot mulberrytech dot com>
- Date: Wed, 12 Jun 2002 19:33:57 +0100
- Subject: Re: [xsl] Grouping and Sorting on value inside group
- Organization: Jeni Tennison Consulting Ltd
- References: <601F6322AD71D5118D6C0003472515290660CEBF@sjmemexc1.stjude.org>
- Reply-to: xsl-list at lists dot mulberrytech dot com
Hi Peter,
I'm new to the thread, so I'm sorry if this has been mentioned before,
but I think that you can do:
<!-- index the data by local name -->
<xsl:key name="names" match="dataset/*/*" use="local-name()" />
<!-- index the data by id -->
<xsl:key name="ids" match="dataset/*/*" use="@dataid" />
<!-- index the data by name and id -->
<xsl:key name="names-and-ids" match="dataset/*/*/value"
use="concat(local-name(), '+', @dataid)" />
and then:
<!-- $sortcol holds the name of the column to sort by -->
<xsl:variable name="sortcol" select="'data_x'" />
<!-- $data holds the data within the document -->
<xsl:variable name="data" select="//dataset/*/*" />
<!-- $uniqueNames holds the first data elements with particular
names -->
<xsl:variable name="uniqueNames"
select="$data[generate-id() =
generate-id(key('names', local-name())[1])]" />
<!-- iterate over the data elements with unique ids -->
<xsl:for-each
select="$data[generate-id() =
generate-id(key('ids', @dataid)[1])]">
<!-- sort them based on the value of the data element with the
same id and the $sortcol element name -->
<xsl:sort
select="key('ids', @dataid)[local-name() = $sortcol][1]/value" />
<!-- $id holds the current id -->
<xsl:variable name="id" select="@dataid" />
<!-- iterate over the $uniqueNames in alphabetical order -->
<xsl:for-each select="$uniqueNames">
<xsl:sort select="local-name()" />
<!-- create an element of that name -->
<xsl:element name="{local-name()}">
<!-- add a dataid attribute with the id -->
<xsl:attribute name="dataid">
<xsl:value-of select="$id" />
</xsl:attribute>
<!-- copy the value from the source data, if there is one -->
<xsl:copy-of select="key('names-and-ids',
concat(local-name(), '+', $id))" />
</xsl:element>
</xsl:for-each>
</xsl:for-each>
---
In XSLT 2.0, you can do:
<xsl:variable name="sortcol" select="'data_x'" />
<xsl:variable name="data" select="//dataset/*/*" />
<xsl:for-each-group select="$data" group-by="@dataid">
<xsl:sort
select="current-group()[local-name() = $sortcol]/value" />
<xsl:variable name="id" select="@dataid" />
<xsl:variable name="sameID" select="current-group()" />
<xsl:for-each-group select="$data" group-by="local-name()">
<xsl:sort select="local-name()" />
<xsl:element name="{local-name()}">
<xsl:attribute name="dataid">
<xsl:value-of select="$id" />
</xsl:attribute>
<xsl:copy-of
select="$sameID[local-name() =
local-name(current())]/value" />
</xsl:element>
</xsl:for-each-group>
</xsl:for-each-group>
although it would probably be better to create a set of unique names
as above, with something like:
<xsl:variable name="sortcol" select="'data_x'" />
<xsl:variable name="data" select="//dataset/*/*" />
<xsl:variable name="uniqueNames"
select="distinct-values(for $d in $data
return local-name())" />
<xsl:for-each-group select="$data" group-by="@dataid">
<xsl:sort
select="current-group()[local-name() = $sortcol]/value" />
<xsl:variable name="id" select="@dataid" />
<xsl:variable name="sameID" select="current-group()" />
<xsl:for-each select="$uniqueNames">
<xsl:sort select="." />
<xsl:element name="{.}">
<xsl:attribute name="dataid">
<xsl:value-of select="$id" />
</xsl:attribute>
<xsl:copy-of
select="$sameID[local-name() = current()]/value" />
</xsl:element>
</xsl:for-each>
</xsl:for-each-group>
Cheers,
Jeni
---
Jeni Tennison
http://www.jenitennison.com/
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list