[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

Re: grouping headers

Subject: Re: grouping headers
From: Jeni Tennison <mail@xxxxxxxxxxxxxxxx>
Date: Fri, 24 Aug 2001 10:42:41 +0100
amsterdam headers
Hi Jeroen,

> I hope I'm making myself clear, I searched the archives for an
> answer but I don't really know what I'm looking for...

I'm surprised that searching for 'grouping' didn't give you an answer!
:)  This is a typical example of grouping-by-value. The most general
approach is the Muenchian Method. In that method, you first define a
key so that you can quickly access all the nodes that have a
particular value.

The name of the key is anything you want (e.g. people). The match
attribute holds a pattern that matches the nodes that you want to
index, in this case the 'person' elements. The use attribute holds a
path from the matched node (the 'person' element) to the value that
you're using to group them (their 'city' child). The key in your
example looks like:

<xsl:key name="people" match="person" use="city" />

With this key in place, you can find all the people from Amsterdam
with:

  key('people', 'Amsterdam')

So given a particular city, in a $city variable, you can find all the
people in that city and generate a list of them with:

  <xsl:for-each select="key('people', $city)">
    <xsl:value-of select="name" /><br />
  </xsl:for-each>

The trickier thing is to find all the cities, since I assume you don't
know that in advance. If you went through all the person elements,
then you would get all the cities, but you would get some of them
repeated several times. You need to make sure that you only get the
first occurrence of each city.

Take 'Amsterdam' as the example. You want to find the city of the
first person element who has a city of 'Amsterdam'. You know how to
get all the person elements who have a city of 'Amsterdam' using the
key (see above). You can use a predicate on the key to get just the
first one:

  key('people', 'Amsterdam')[1]

You need to look through all the person elements and find those that
are the first returned for their particular city. This involves
comparing two nodes; I find the most intuitive way is to use the
generate-id() function, as follows:

  generate-id() = generate-id(key('people', city)[1])

So to get a list of all the person elements that are the first with a
particular city, use:

  person[generate-id() = generate-id(key('people', city)[1])]

You can use set logic instead, if you prefer:

  person[count(.|key('people', city)[1]) = 1]

So you can iterate over those to get a list of them:

  <xsl:for-each select="person[count(.|key('people', city)[1]) = 1]">
    <xsl:sort select="city" />
    <!-- variable used for clarity -->
    <xsl:variable name="city" select="city" />
    <xsl:value-of select="$city" /><br />
    <xsl:for-each select="key('people', $city)">
      <xsl:value-of select="name" /><br />
    </xsl:for-each>
    <br />
  </xsl:for-each>

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

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2013 All Rights Reserved.