RE: [xsl] xsl:key and grouping & books

Subject: RE: [xsl] xsl:key and grouping & books
From: Roger.Menday@xxxxxxxxxxxxxx
Date: Tue, 27 Feb 2001 13:28:51 -0000
Perfect. Back on track again. 
Evidently the problems stemmed from the definition of the key.

Thanks very much for the good advice.

Incidentally, is there a consensus on good xsl books ? 
I have the Michael Kay book (good, but heavy to carry around and read on the
and the intro to Xpath (particularly) in XML in a Nutshell I found quite
what 'the xsl companion' ? the 3 three reviews of this at
are not 
very favourable, but I suspect that all 3 are by the same person. 


-----Original Message-----
From: Jeni Tennison [mailto:mail@xxxxxxxxxxxxxxxx]
Sent: 27 February 2001 11:55
To: Roger.Menday@xxxxxxxxxxxxxx
Cc: XSL-List@xxxxxxxxxxxxxxxxxxxxxx
Subject: Re: [xsl] xsl:key and grouping

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
# (that's the [1] predicate on the key() function doing its

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

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

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

     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" />
   <br /><br />

I hope that helps,


Jeni Tennison

 XSL-List info and archive:

If you have received this e-mail in error or wish to read our e-mail 
disclaimer statement and monitoring policy, please refer to or contact the sender.

 XSL-List info and archive:

Current Thread