home movie radio music chord lyrics book game Dictionary clip
HOME HAND MADE RADIO SHOP CHORD LYRICS BOOKS GAME Dictionary Clip
[ Team LiB ] Previous Section Next Section

9.1 Numbered Lists

As usual, to illustrate a concept, I'll begin with a simple example. In the directory examples/ch09, you'll find the document canada.xml, which contains a list of all the Canadian provinces, in alphabetical order, as shown in Example 9-1.

Example 9-1. An XML list of Canadian provinces and territories
<?xml version="1.0" encoding="UTF-8"?>
   
<provinces>
 <name>Alberta</name>
 <name>British Columbia</name>
 <name>Manitoba</name>
 <name>New Brunswick</name>
 <name>Newfoundland and Labrador</name>
 <name>Northwest Territories</name>
 <name>Nova Scotia</name>
 <name>Nunavut</name>
 <name>Ontario</name>
 <name>Prince Edward Island</name>
 <name>Quebec</name>
 <name>Saskatchewan</name>
 <name>Yukon</name>
</provinces>

You can generate numbers manually from the XPath function position( ) to number a list from canada.xml. Example 9-2, position.xsl, shows you one way to do this.

Example 9-2. A stylesheet using node position for numbering
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
   
 <xsl:template match="provinces">
   <xsl:apply-templates select="name"/>
 </xsl:template>
   
 <xsl:template match="name">
  <xsl:value-of select="position(  )"/>
  <xsl:text>. </xsl:text>
  <xsl:value-of select="."/>
  <xsl:text>&#10;</xsl:text>
 </xsl:template>
   
</xsl:stylesheet>

In the first value-of element in the template rule that matches name, the position( ) function returns an integer reflecting the current position in the current node list. The current node list at this point consists of all the name nodes in the source tree. After giving you the position, the template inserts some text, then the text node child of the current name, then a linefeed. When you apply the stylesheet like this:

xalan canada.xml position.xsl

you will get the output shown in Example 9-3.

Example 9-3. A list of numbered provinces, produced by running position.xsl
1. Alberta
2. British Columbia
3. Manitoba
4. New Brunswick
5. Newfoundland and Labrador
6. Northwest Territories
7. Nova Scotia
8. Nunavut
9. Ontario
10. Prince Edward Island
11. Quebec
12. Saskatchewan
13. Yukon

One pitfall of using position( ) is that if you use apply-templates without a select attribute, the whitespace text nodes are numbered as well. position( ) is actually counting nodes—that is, it is counting the nodes in processing order, regardless of where they are in the tree. Don't be surprised if you get strange numbers in output as a result of position( ) quietly counting whitespace nodes!

If you are producing HTML or XHTML output, remember that you can also generate numbered lists using the ol and li elements.


9.1.1 The number Element

You can get by just using position( ), but XSLT's number instruction element is far more powerful. Example 9-4, the stylesheet number.xsl, is similar to Example 8-2, sort.xsl in examples/ch08, but with at least one obvious difference—the presence of the number instruction element.

Example 9-4. An XSLT stylesheet using the number element
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
   
 <xsl:template match="provinces">
   <xsl:apply-templates select="name"/>
 </xsl:template>
   
 <xsl:template match="name">
  <xsl:number format=" 1. "/>
  <xsl:value-of select="."/>
  <xsl:text>&#10;</xsl:text>
 </xsl:template>
   
</xsl:stylesheet>

The template that matches name inserts a formatted number into the result tree using number, followed by the string value of each text node child of name that it finds. This is followed by a line break (&#10;). Without using position( ), the number is derived from the position of the node in the source tree, not the current node list. When number is instantiated, it numbers all the name elements in the source document.

The inserted number is formatted according to the contents of the optional format attribute. The format attribute does the job that the first text element in position.xsl did. All of the attributes of number are optional, by the way, but if you don't use format, you might find that your numbers don't look very good.

The content of format is a string that describes how you want the number formatted in output. In the case of number.xsl, format contains first a space followed by the digit 1, followed by a period (.), and ending with another space. The digit 1 will be replaced by an incremented number when the transformation takes place.

To see how this looks, transform canada.xml with number.xsl with:

xalan canada.xml number.xsl

and you will get the results shown in Example 9-5.

Example 9-5. The results of using the number.xsl stylesheet
 1. Alberta
 2. British Columbia
 3. Manitoba
 4. New Brunswick
 5. Newfoundland and Labrador
 6. Northwest Territories
 7. Nova Scotia
 8. Nunavut
 9. Ontario
 10. Prince Edward Island
 11. Quebec
 12. Saskatchewan
 13. Yukon

9.1.2 The count Attribute

Without the count attribute, by default, only the nodes of the same name and type as the current node are counted. If the count attribute is present, however, the nodes that match the pattern in count are counted. For example, when applied to canada.xml, the stylesheet count.xsl, in Example 9-6, produces the same result as number.xsl, though the nodes you want to count are made explicit in the count attribute.

Example 9-6. Making the count explicit
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
   
 <xsl:template match="provinces">
   <xsl:apply-templates select="name"/>
 </xsl:template>
   
 <xsl:template match="name">
  <xsl:number count="name" format=" 1. "/>
  <xsl:value-of select="."/>
  <xsl:text>&#10;</xsl:text>
 </xsl:template>
   
</xsl:stylesheet>

9.1.3 More on Formatting

The output from number.xsl and count.xsl looks very similar to what you get with position.xsl, but you can line things up a bit better by adding a tab to the format attribute, as shown in Example 9-7, the stylesheet tab.xsl.

Example 9-7. Modifying number formatting
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
   
 <xsl:template match="provinces">
   <xsl:apply-templates select="name"/>
 </xsl:template>
   
 <xsl:template match="name">
  <xsl:number format=" 01.&#09;"/>
  <xsl:value-of select="."/>
  <xsl:text>&#10;</xsl:text>
 </xsl:template>
   
</xsl:stylesheet>

The value of the format attribute in tab.xsl is a little different than what you saw earlier. Instead of following the period with a space, there is a decimal character reference (&#09;) for a horizontal tab. (You could also write this as a hexadecimal reference, that is, &#x9;.) As you'll see, the tab will help line up the output.

The digit 1 has also been replaced by 01. This indicates that you want to use at least two places for your numbers instead of one. To see what I mean, transform canada.xml with tab.xsl with this command:

xalan canada.xml tab.xsl

Example 9-8 shows the result.

Example 9-8. The results of explicit formatting using tab.xsl
 01.    Alberta
 02.    British Columbia
 03.    Manitoba
 04.    New Brunswick
 05.    Newfoundland and Labrador
 06.    Northwest Territories
 07.    Nova Scotia
 08.    Nunavut
 09.    Ontario
 10.    Prince Edward Island
 11.    Quebec
 12.    Saskatchewan
 13.    Yukon

Because tab.xsl formats the number with two places, you will get a leading zero for the numbers 1-9. Notice also that, because of the addition of the tab, all the text lines up nicely.

    [ Team LiB ] Previous Section Next Section