2.5. Looping and Sorting
As shown throughout this chapter, you can use
<xsl:apply-templates ...> to search for
patterns in an XML document. This type of processing is sometimes
referred to as a " data driven" approach because the
data of the XML file drives the selection process. Another style of
XSLT programming is called "template driven," which
means that the template's code tends to drive the selection
process.
2.5.1. Looping with <xsl:for-each>
Sometimes it is convenient to explicitly drive the selection process
with an
<xsl:for-each>
element, which is
reminiscent of traditional programming techniques. In this approach,
you explicitly loop over a collection of nodes without instantiating
a separate template as <xsl:apply-templates>
does. The syntax for <xsl:for-each> is as
follows:
<xsl:for-each select="president">
...content for each president element
</xsl:for-each>
The select attribute can contain any XPath
location path, and the loop will iterate over each element in the
resulting node set. In this example, the context is
<president> for all content within the loop.
Nested loops are possible and could be used to loop over the list of
<vicePresident> elements.
2.5.2. Sorting
Sorting can be
applied in either a data-driven or template-driven approach. In
either case,
<xsl:sort> is added
as a child element to something else. By adding several consecutive
<xsl:sort> elements, you can accomplish
multifield sorting. Each sort can be in ascending or descending
order, and the data type for sorting is either
"number" or "text". The sort
order defaults to ascending. Some examples of
<xsl:sort> include:
<xsl:sort select="first"/>
<xsl:sort select="last" order="descending"/>
<xsl:sort select="term/@from" order="descending" data-type="number"/>
<xsl:sort select="name/first" data-type="text" case-order="upper-first"/>
In the last line, the case-order attribute
specifies that uppercase letters should be alphabetized before
lowercase letters. The other accepted value for this attribute is
lower-first. According to the specification, the
default behavior is "language dependent."
2.5.3. Looping and Sorting Examples
The easiest way to learn about looping
and sorting is to play around with a lot of small examples. The code
in Example 2-9 applies numerous different looping
and sorting strategies to our list of presidents. Comments in the
code indicate what is happening at each step.
Example 2-9. Looping and sorting
<?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"/>
<xsl:template match="/">
<html>
<body>
<h1>Sorting Examples</h1>
<xsl:apply-templates select="presidents"/>
</body>
</html>
</xsl:template>
<!--********************************************************************
** presidents template
*****************************************************************-->
<xsl:template match="presidents">
<!--*****************************************************************
** Sorting using xsl:for-each
**************************************************************-->
<h2>All presidents sorted by first name using xsl:for-each</h2>
<xsl:for-each select="president">
<xsl:sort select="name/first"/>
<xsl:apply-templates select="name"/>
</xsl:for-each>
<!--*****************************************************************
** Sorting using xsl:apply-templates
**************************************************************-->
<h2>All presidents sorted by first name using xsl:apply-templates</h2>
<xsl:apply-templates select="president/name">
<xsl:sort select="first"/>
</xsl:apply-templates>
<h2>All presidents sorted by date using xsl:apply-templates</h2>
<xsl:apply-templates select="president/name">
<xsl:sort select="../term/@from" data-type="number" order="descending"/>
</xsl:apply-templates>
<!--*****************************************************************
** Multi-field sorting
**************************************************************-->
<h2>Multi-field sorting example</h2>
<xsl:apply-templates select="president/name">
<xsl:sort select="last"/>
<xsl:sort select="first" order="descending"/>
</xsl:apply-templates>
<!--*****************************************************************
** Nested xsl:for-each loops
**************************************************************-->
<h2>All presidents and vice presidents using xsl:for-each</h2>
<ul>
<xsl:for-each select="president">
<xsl:sort select="name/first" order="descending"/>
<li>
<xsl:apply-templates select="name"/>
</li>
<ul>
<xsl:for-each select="vicePresident">
<xsl:sort select="name/first"/>
<li>
<xsl:apply-templates select="name"/>
</li>
</xsl:for-each>
</ul>
</xsl:for-each>
</ul>
<!--*****************************************************************
** Same as previous, only using xsl:apply-templates
**************************************************************-->
<h2>All presidents and vice presidents using xsl:apply-templates</h2>
<ul>
<xsl:apply-templates select="president">
<xsl:sort select="name/first" order="descending"/>
</xsl:apply-templates>
</ul>
</xsl:template>
<!--*****************************************************************
** 'president' template, outputs the president's name and vice
** president's name.
**************************************************************-->
<xsl:template match="president">
<li>
<xsl:apply-templates select="name"/>
</li>
<ul>
<xsl:for-each select="vicePresident">
<xsl:sort select="name/first"/>
<li>
<xsl:apply-templates select="name"/>
</li>
</xsl:for-each>
</ul>
</xsl:template>
<!--*****************************************************************
** name template, outputs first, middle, and last name
**************************************************************-->
<xsl:template match="name">
<xsl:text disable-output-escaping="yes">&nbsp;</xsl:text>
<xsl:value-of select="first"/>
<xsl:text disable-output-escaping="yes">&nbsp;</xsl:text>
<xsl:value-of select="middle"/>
<xsl:text disable-output-escaping="yes">&nbsp;</xsl:text>
<xsl:value-of select="last"/>
<br/>
</xsl:template>
</xsl:stylesheet>
Notice that when applying a sort to
<xsl:apply-templates>, that element can no
longer be an empty element. Instead, one or more
<xsl:sort> elements are added as children of
<xsl:apply-templates>. You should also note
that sorting cannot occur in the <xsl:template
match="name"> element. The reason for this is simple: at
the <xsl:apply-templates> end, you have a
list of nodes to sort. By the time the processing reaches
<xsl:template match="name">, the search has
narrowed down to a single <name>, so there
is no node list left to sort.
 |  |  | | 2.4. XPath Basics |  | 2.6. Outputting Dynamic Attributes |
Copyright © 2002 O'Reilly & Associates. All rights reserved.
|