[xsl] Grouping and Sorting on value inside group

Subject: [xsl] Grouping and Sorting on value inside group
From: "Hunsberger, Peter" <Peter.Hunsberger@xxxxxxxxxx>
Date: Mon, 10 Jun 2002 16:55:51 -0500
As I've mentioned a couple of times recently I have a problem with keys that
I've been having trouble with. Basically, I have to rotate some data

x | c b a d
y | e _ d _
z | _ h f g

to 

   x   y  z
   --------
   c  e  _
   b  _  h
   a  d  f
   d  _  g	

Where there is a common id to group on.  Moreover I need to sort the
resultant rows based on a variable that will name a particular column. 

Essentially, I have some XML of the form:

    <dataset>
	<groupa>
		<data_x dataid="1">
			<value>c</value>
		</data>
		<data_x dataid="2">
			<value>b</value>
		</data>
		<data_x dataid="3">
			<value>a</value>
		</data>
		<data_x dataid="4">
			<value>d</value>
		</data>
		<data_y dataid="1">
			<value>e</value>
		</data>
		<data_y dataid="2"/>
		<data_y dataid="3">
			<value>d</value>
		</data>
		<data_y dataid="4"/>
		<data_z dataid="1"/>
		<data_z dataid="2">
			<value>h</value>
		</data>
		<data_z dataid="3">
			<value>f</value>
		</data>
		<data_z dataid="4">
			<value>g</value>
		</data>
	</groupa>
   </dataset>

This needs to be transformed into:

	<groupa>
		<data_x dataid="1">
			<value>c</value>
		</data>
		<data_y dataid="1">
			<value>e</value>
		</data>
		<data_z dataid="1"/>
		<data_x dataid="2">
			<value>b</value>
		</data>
		<data_y dataid="2"/>
		<data_z dataid="2">
			<value>h</value>
		</data>
		<data_x dataid="3">
			<value>a</value>
		</data>
		<data_y dataid="3">
			<value>d</value>
		</data>
		<data_z dataid="3">
			<value>f</value>
		</data>
		<data_x dataid="4">
			<value>d</value>
		</data>
		<data_y dataid="4"/>
		<data_z dataid="4">
			<value>g</value>
		</data>
	</groupa>

Where there could be multiple groups, but the "data" elements in each group
are unique.  I can do the grouping using:

   <xsl:key name="dataids" match="dataset/*/*"
use="concat(local-name(..),@dataId)"/>

and then several templates down:

   <xsl:for-each select="//dataset/*/*[generate-id() =
generate-id(key('dataids', concat(local-name(..),@dataId)))]">

but this has the disadvantage of using the // reference to the dataset node.
Is it possible to use an additional(?) key to do this more efficiently?
Since the groups are distinct I believe I  don't need to concat with
local-name() but simply "use" @dataid.  Does using the local-name help or
hurt?

Next, is it possible to sort this grouping by the text of the value nodes?
Eg; if I get passed a parameter of "data_y" I'd like to sort the "data"
nodes by the ordering of the id's corresponding to the values in the
"data_y" node.  In this case:

	<groupa>
		<data_x dataid="3">
			<value>a</value>
		</data>
		<data_y dataid="3">
			<value>d</value>
		</data>
		<data_z dataid="3">
			<value>f</value>
		</data>
		<data_x dataid="1">
			<value>c</value>
		</data>
		<data_y dataid="1">
			<value>e</value>
		</data>
		<data_z dataid="1"/>
		<data_x dataid="2">
			<value>b</value>
		</data>
		<data_y dataid="2"/>
		<data_z dataid="2">
			<value>h</value>
		</data>
		<data_x dataid="4">
			<value>d</value>
		</data>
		<data_y dataid="4"/>
		<data_z dataid="4">
			<value>g</value>
		</data>
	</groupa>

I'm fine with nodes with no value text child node being sorted first or
last...  This can be done as a two stage transformation; the sorting can be
done first or in the same transformation as the grouping, but the grouping
has to be done in the last transformation.

Peter Hunsberger

Phone: 901-495-5252
E-mail: Peter.Hunsberger@xxxxxxxxxx


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread