11.5 Grouping with Keys

An interesting problem that you can solve with keys comes under the rubric of grouping. Grouping in XSLT refers to the process of grouping nodes logically with related nodes in the output. The problem that grouping solves is that nodes may not be grouped to your liking in the source document. For an example, look at group.xml:

<?xml version="1.0" encoding="US-ASCII"?> <?xml-stylesheet href="group.xsl" type="text/xsl"?> <uscities>  <western>   <uscity state="Nevada">Las Vegas</uscity>   <uscity state="Arizona">Phoenix</uscity>   <uscity state="California">San Francisco</uscity>   <uscity state="Nevada">Silver City</uscity>   <uscity state="Washington">Seattle</uscity>   <uscity state="Montana">Missoula</uscity>   <uscity state="Washington">Spokane</uscity>   <uscity state="California">Los Angeles</uscity>   <uscity state="Utah">Salt Lake City</uscity>   <uscity state="California">Sacramento</uscity>   <uscity state="Idaho">Boise</uscity>   <uscity state="Montana">Butte</uscity>   <uscity state="Washington">Tacoma</uscity>   <uscity state="Montana">Helena</uscity>   <uscity state="Oregon">Portland</uscity>   <uscity state="Nevada">Reno</uscity>   <uscity state="Oregon">Salem</uscity>   <uscity state="Oregon">Eugene</uscity>   <uscity state="Utah">Provo</uscity>   <uscity state="Idaho">Twin Falls</uscity>   <uscity state="Utah">Ogden</uscity>   <uscity state="Arizona">Flagstaff</uscity>   <uscity state="Idaho">Idaho Falls</uscity>   <uscity state="Arizona">Tucson</uscity>  </western> </uscities>

The uscity nodes in group.xml list western U.S. cities at random, not in an organized way as you might prefer. One feature that can help is that each uscity node has a state attribute. The XSLT grouping technique I'll show you can organize the output according to state, also listing each appropriate city with the given state. This grouping technique is popularly known as the Muenchian method, after Steve Muench (http://www.oreillynet.com/pub/au/609), the really smart guy who discovered the method.

The Muenchian method of grouping employs keys together with the generate-id() function (you learned about generate-id() back in Chapter 5). There are other grouping methods in XSLT, such as one that uses the preceding-sibling axis, but I've chosen to show you only the Muenchian method here for two reasons: it is the most efficient or fastest method of grouping; and it is the most similar to the new grouping method using the XSLT 2.0 element for-each-group, which you will see in Chapter 16.

You can find discussions of other grouping methods in Michael Kay's XSLT Programmer's Reference (Wrox) or Doug Tidwell's XSLT (O'Reilly), but both authors also recommend the Muenchian method as being the most efficient.


The stylesheet group.xsl assembles its output according to the Muenchian method, which I will explain in a moment:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html"/> <xsl:key name="list" match="uscity" use="@state"/> <xsl:template match="/"> <html> <head> <title>Western State Cities</title></head> <style type="text/css"> h2 {font-family:verdana,helvetica,sans-serif;font-size:13pt} li {font-family:verdana,helvetica,sans-serif;font-size:11pt} </style> <body> <xsl:for-each select="/uscities/western/uscity[generate-id(.)=generate-id(key('list', @state))]/@state"> <xsl:sort/> <h2><xsl:value-of select="."/></h2> <ul>  <xsl:for-each select="key('list', .)">   <xsl:sort/>   <li><xsl:value-of select="."/></li>  </xsl:for-each> </ul> </xsl:for-each> </body> </html> </xsl:template> </xsl:stylesheet>

The secret to understanding the Muenchian method lies in its use of keys and the generate-id() function. Near the beginning of group.xsl, the key named list is defined. This key is used to efficiently find state attributes on uscity elements. The generate-id() function is used with the key() function in for-each to process the first node in a set. In this example, it finds the first node whose state attribute identifies a given state and outputs the name of the state found in the attribute.

Following that, another for-each processes each other node in the document matching the previous for-each, also using key(). The value-of under this for-each outputs the name of the given city. The sort element under the for-each elements sorts the nodes in alphabetical order.

It's a little complicated, but it works well. Test it with the command:

xalan -m -i 1 group.xml group.xsl

and you will get nicely grouped HTML output that looks like this:

<html>  <head>   <title>Western State Cities</title>  </head>  <style type="text/css"> h2 {font-family:verdana,helvetica,sans-serif;font-size:13pt} li {font-family:verdana,helvetica,sans-serif;font-size:11pt} </style>  <body>   <h2>Arizona</h2>   <ul>    <li>Flagstaff</li>    <li>Phoenix</li>    <li>Tucson</li>   </ul>   <h2>California</h2>   <ul>    <li>Los Angeles</li>    <li>Sacramento</li>    <li>San Francisco</li>   </ul>   <h2>Idaho</h2>   <ul>    <li>Boise</li>    <li>Idaho Falls</li>    <li>Twin Falls</li>   </ul>   <h2>Montana</h2>   <ul>    <li>Butte</li>    <li>Helena</li>    <li>Missoula</li>   </ul>   <h2>Nevada</h2>   <ul>    <li>Las Vegas</li>    <li>Reno</li>    <li>Silver City</li>   </ul>   <h2>Oregon</h2>   <ul>    <li>Eugene</li>    <li>Portland</li>    <li>Salem</li>   </ul>   <h2>Utah</h2>   <ul>    <li>Ogden</li>    <li>Provo</li>    <li>Salt Lake City</li>   </ul>   <h2>Washington</h2>   <ul>    <li>Seattle</li>    <li>Spokane</li>    <li>Tacoma</li>   </ul>  </body> </html>

In the output, under each alphabetically listed state, comes an alphabetical list of cities. That's what grouping can do for you. Because it has an XML stylesheet PI, you can also open group.xml in a browser to see the output. Figure 11-1 shows group.xml transformed by group.xsl in the Mozilla Firebird browser that appears with the Mozillazine (MZ) theme.

Figure 11-1. group.xml in Mozilla Firebird
figs/lxsl_1101.gif


Learning XSLT
Learning XSLT
ISBN: 0596003277
EAN: 2147483647
Year: 2003
Pages: 164

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net