Section 10.5.  XSLT Concepts

JavaScript Editor Free JavaScript Editor     JavaScript Debugger 




Main Page

Previous Page
Next Page

10.5. XSLT Concepts

When developing an XSL style sheet, I usually find myself using only two of the XSL functions shown earlier: the key() function and the generate-id() function, both of which are indispensable when doing something unique to XSL style sheets. I am referring to something called Muenchian grouping.

Muenchian grouping, invented by Steve Muench, the XML Evangelist of the Oracle Corporation, is a method of grouping nodes based upon their values. Although I can describe how it works, it is probably a better idea to take a look at the example of Muenchian grouping shown in Listing 10-13. After that, we take it apart to see how it works.

Listing 10-13. A Muenchian Grouping Example

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes" />
  <xsl:key name="keyBook" match="book" use="series" />

  <xsl:template match="/">

    <xsl:element name="table">
       <xsl:attribute name="width">100%</xsl:attribute>

       <xsl:apply-templates select="//book[1]" mode="header" />
    <xsl:apply-templates select="//book[generate-id(.) = generate-
id(key('keyBook',series)[1])]" />
       <xsl:apply-templates select="//book[string-length(series) =
0]/series" />
  </xsl:element>

   </xsl:template>

<xsl:template match="book">

     <xsl:variable name="key">
       <xsl:value-of select="series" />
     </xsl:variable>

     <xsl:apply-templates select="//series[node() = $key]" />

   </xsl:template>

   <xsl:template match="series">

   <xsl:element name="tr">
     <xsl:apply-templates select="parent::node()/*" mode="cell" />
   </xsl:element>

</xsl:template>

<xsl:template match="*" mode="cell">

  <xsl:element name="td">
      <xsl:attribute name="align">left</xsl:attribute>

    <xsl:value-of select="." />
  </xsl:element>

   </xsl:template>

   <xsl:template match="book" mode="header">

  <xsl:element name="tr">
   <xsl:apply-templates select="./*" mode="columnHeader" />
  </xsl:element>

   </xsl:template>

   <xsl:template match="*" mode="columnHeader">

     <xsl:variable
name="lowerCase">qwertyuiopasdfghjklzxcvbnm</xsl:variable>
     <xsl:variable
name="upperCase">QWERTYUIOPASDFGHJKLZXCVBNM</xsl:variable>

     <xsl:element name="th">
       <xsl:attribute name="width">33%</xsl:attribute>

       <xsl:value-of select="translate(name(.),$lowerCase,$upperCase)" />
     </xsl:element>

   </xsl:template>

</xsl:stylesheet>

The element that starts the whole ball rolling is the key element, which creates a cross-reference based upon the node specified by the use attribute. Using the series element as the key results in an index consisting of The Lord of the Rings and Lord Darcy, with the book The Way Station left out because its series element is null. This cross-reference is accessed using the key function, which accepts two parameters: the name from the key element and the node.

Another function that plays an integral part in Muenchian grouping is the generate-id function. This function, well, generates a unique ID for every node in an XML document every time that the document is processed. So the XPath statement //book[generate-id(.) = generate-id(key('keyBook',series)[1])] locates the first element with each unique key from the cross-reference and applies the matching template. The matching template then uses the unique series to select the matching elements.

It is all pretty basic XSLT and XPath stuff, although it does have a tendency to make grown men whimper like little scared puppies. If it doesn't, here is one that will put someone over the edge: Imagine trying to group based upon multiple criteria, such as author and series. Although it isn't done very often, and you'll probably never have to do it, I'll give you a hint: Concatenate the elements using the concat function.


Previous Page
Next Page




JavaScript Editor Free JavaScript Editor     JavaScript Debugger


©