Re: [xsl] xsl:key and grouping

Subject: Re: [xsl] xsl:key and grouping
From: Jeni Tennison <mail@xxxxxxxxxxxxxxxx>
Date: Tue, 27 Feb 2001 11:55:27 +0000
Hi Roger,

> I wish to order the information via car, rather than person. This
> all works fine until I give a particular person more than one
> favourite car element, which either the xsl:key doesn't pick up, or
> that I don't use when accessing the key. i.e. in the example above
> the transformed xml fails to pick up the all the cars.

In the example, the key has been set up with:

  <xsl:key name="carkey" match="item" use="car" />

This groups all the 'item' elements according to their 'car' element
child(ren). Now you've added more than one car per item, each item
might be retrievable through lots of cars. However, if the context
node is an item with three car child elements - 'Mini', 'Fiesta' and
'Metro' - and you do:

  key('carkey', car)

then you will retrieve all the items that have any car subelements
with the values 'Mini', 'Fiesta' or 'Metro'.

When you're using the Muenchian method of grouping, in particular:

  item[ count(. | key('carkey', car)[1])=1 ]

it kinda assumes that you're only going to be using one key value for
each of the things that you're picking.  In your sample, Mary is the
first item for the Mini, Fiesta and Metro cars, but she'll only be
selected as the first item for the 'Mini' because all the rest are
ignored (that's the [1] predicate on the key() function doing its
work).

So, first change the key so that you're grouping the car elements
instead:

  <xsl:key name="carkey" match="car" use="." />

Then apply templates to the cars that are unique rather than the items
that have unique cars:

  <xsl:apply-templates
     select="item/car[count(.|key('carkey', .)[1]) = 1]" />

Have a template that matches the unique cars and outputs the relevant
stuff about it:

<xsl:template match="car">
   <h4><xsl:value-of select="." /></h4>
   <!-- cycle over the items for the relevant car -->
   <xsl:for-each select="key('carkey', .)/parent::item">
      <xsl:sort select="name" />
      <xsl:apply-templates select="name" />
   </xsl:for-each>
   <br /><br />
</xsl:template>

I hope that helps,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/



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


Current Thread