| <xsl:number> | |
| Counts something. It is most often used to number parts of a document, although it can also be used to format a numeric value. | |
| Category | |
|
Instruction |
|
| Required Attributes | |
|
None. |
|
| Optional Attributes | |
|
|
| Content | |
|
None. <xsl:number> is an empty element. |
|
| Appears in | |
|
<xsl:number> appears inside a template. |
|
| Defined in | |
|
XSLT section 7.7, Numbering. |
|
| Example | |
|
To fully illustrate how <xsl:number> works, we'll need an XML document with many things to count. Here's the document we'll use:
<?xml version="1.0"?>
<book>
<chapter>
<title>Alfa Romeo</title>
<sect1>
<title>Bentley</title>
</sect1>
<sect1>
<title>Chevrolet</title>
<sect2>
<title>Dodge</title>
<sect3>
<title>Eagle</title>
</sect3>
</sect2>
</sect1>
</chapter>
<chapter>
<title>Ford</title>
<sect1>
<title>GMC</title>
<sect2>
<title>Honda</title>
<sect3>
<title>Isuzu</title>
</sect3>
<sect3>
<title>Javelin</title>
</sect3>
<sect3>
<title>K-Car</title>
</sect3>
<sect3>
<title>Lincoln</title>
</sect3>
</sect2>
<sect2>
<title>Mercedes</title>
</sect2>
<sect2>
<title>Nash</title>
<sect3>
<title>Opel</title>
</sect3>
<sect3>
<title>Pontiac</title>
</sect3>
</sect2>
<sect2>
<title>Quantum</title>
<sect3>
<title>Rambler</title>
</sect3>
<sect3>
<title>Studebaker</title>
</sect3>
</sect2>
</sect1>
<sect1>
<title>Toyota</title>
<sect2>
<title>Um, is there a car that starts with "U"?</title>
</sect2>
</sect1>
<sect1>
<title>Volkswagen</title>
</sect1>
</chapter>
</book>
We'll use <xsl:number> in several different ways to illustrate the various options we have in numbering things. We'll look at the stylesheet and the results, then we'll discuss them. Here's the stylesheet:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:variable name="newline">
<xsl:text>
</xsl:text>
</xsl:variable>
<xsl:template match="/">
<xsl:value-of select="$newline"/>
<xsl:apply-templates select="book" mode="number-1"/>
<xsl:apply-templates select="book" mode="number-2"/>
<xsl:apply-templates select="book" mode="number-3"/>
<xsl:apply-templates select="book" mode="number-4"/>
<xsl:apply-templates select="book" mode="number-5"/>
<xsl:apply-templates select="book" mode="number-6"/>
<xsl:apply-templates select="book" mode="number-7"/>
</xsl:template>
<xsl:template match="book" mode="number-1">
<xsl:text>Test #1: level="multiple",
count="chapter|sect1|sect2|sect3",
format="1.1.1.1. "</xsl:text>
<xsl:value-of select="$newline"/>
<xsl:value-of select="$newline"/>
<xsl:for-each select="chapter|.//sect1|.//sect2|.//sect3">
<xsl:number level="multiple" count="chapter|sect1|sect2|sect3"
format="1.1.1.1. "/>
<xsl:value-of select="title"/>
<xsl:value-of select="$newline"/>
</xsl:for-each>
<xsl:value-of select="$newline"/>
</xsl:template>
<xsl:template match="book" mode="number-2">
<xsl:text>Test #2: level="any",
count="chapter|sect1|sect2|sect3",
format="1. "</xsl:text>
<xsl:value-of select="$newline"/>
<xsl:value-of select="$newline"/>
<xsl:for-each select="chapter|.//sect1|.//sect2|.//sect3">
<xsl:number level="any" count="chapter|sect1|sect2|sect3"
format="1. "/>
<xsl:value-of select="title"/>
<xsl:value-of select="$newline"/>
</xsl:for-each>
<xsl:value-of select="$newline"/>
</xsl:template>
<xsl:template match="book" mode="number-3">
<xsl:text>Test #3: level="single",
count="chapter|sect1|sect2|sect3",
format="1.1.1.1. "</xsl:text>
<xsl:value-of select="$newline"/>
<xsl:value-of select="$newline"/>
<xsl:for-each select="chapter|.//sect1|.//sect2|.//sect3">
<xsl:number level="single" count="chapter|sect1|sect2|sect3"
format="1.1.1.1. "/>
<xsl:value-of select="title"/>
<xsl:value-of select="$newline"/>
</xsl:for-each>
<xsl:value-of select="$newline"/>
</xsl:template>
<xsl:template match="book" mode="number-4">
<xsl:text>Test #4: level="multiple",
select=".//sect2",
count="chapter|sect1|sect2",
format="I-A-i: "</xsl:text>
<xsl:value-of select="$newline"/>
<xsl:value-of select="$newline"/>
<xsl:for-each select=".//sect2">
<xsl:number level="multiple" count="chapter|sect1|sect2"
format="I-A-i: "/>
<xsl:value-of select="title"/>
<xsl:value-of select="$newline"/>
</xsl:for-each>
<xsl:value-of select="$newline"/>
</xsl:template>
<xsl:template match="book" mode="number-5">
<xsl:text>Test #5: level="any",
count="[various elements]"
from="[various elements]"
format="1.1.1.1. "</xsl:text>
<xsl:value-of select="$newline"/>
<xsl:value-of select="$newline"/>
<xsl:for-each select=".//sect3">
<xsl:number level="any" from="book" count="chapter" format="1."/>
<xsl:number level="any" from="chapter" count="sect1" format="1."/>
<xsl:number level="any" from="sect1" count="sect2" format="1."/>
<xsl:number level="any" from="sect2" count="sect3" format="1. "/>
<xsl:value-of select="title"/>
<xsl:value-of select="$newline"/>
</xsl:for-each>
<xsl:value-of select="$newline"/>
</xsl:template>
<xsl:template match="book" mode="number-6">
<xsl:text>Test #6: level="any",
count="chapter|sect1|sect2|sect3",
grouping-separator=",",
using a variable to start counting at 1000.</xsl:text>
<xsl:value-of select="$newline"/>
<xsl:value-of select="$newline"/>
<xsl:for-each select="chapter|.//sect1|.//sect2|.//sect3">
<xsl:variable name="value1">
<xsl:number level="any" count="chapter|sect1|sect2|sect3"/>
</xsl:variable>
<xsl:number value="$value1 + 999"
grouping-separator="." grouping-size="3"/>
<xsl:text>. </xsl:text>
<xsl:value-of select="title"/>
<xsl:value-of select="$newline"/>
</xsl:for-each>
<xsl:value-of select="$newline"/>
</xsl:template>
<xsl:template match="book" mode="number-7">
<xsl:text>Test #7: level="multiple",
count="chapter|sect1|sect2|sect3",
format="1.1.1.1. ",
selecting up to the first two <sect1> elements from chapter 2.</xsl:text>
<xsl:value-of select="$newline"/>
<xsl:value-of select="$newline"/>
<xsl:for-each select="chapter[2]/sect1[position() < 3]">
<xsl:for-each select="chapter|.//sect1|.//sect2|.//sect3">
<xsl:number level="multiple" count="chapter|sect1|sect2|sect3"
format="1.1.1.1. "/>
<xsl:value-of select="title"/>
<xsl:value-of select="$newline"/>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Here are our results:
Test #1: level="multiple",
count="chapter|sect1|sect2|sect3",
format="1.1.1.1. "
1. Alfa Romeo
1.1. Bentley
1.2. Chevrolet
1.2.1. Dodge
1.2.1.1. Eagle
2. Ford
2.1. GMC
2.1.1. Honda
2.1.1.1. Isuzu
2.1.1.2. Javelin
2.1.1.3. K-Car
2.1.1.4. Lincoln
2.1.2. Mercedes
2.1.3. Nash
2.1.3.1. Opel
2.1.3.2. Pontiac
2.1.4. Quantum
2.1.4.1. Rambler
2.1.4.2. Studebaker
2.2. Toyota
2.2.1. Um, is there a car that starts with "U"?
2.3. Volkswagen
Test #2: level="any",
count="chapter|sect1|sect2|sect3",
format="1. "
1. Alfa Romeo
2. Bentley
3. Chevrolet
4. Dodge
5. Eagle
6. Ford
7. GMC
8. Honda
9. Isuzu
10. Javelin
11. K-Car
12. Lincoln
13. Mercedes
14. Nash
15. Opel
16. Pontiac
17. Quantum
18. Rambler
19. Studebaker
20. Toyota
21. Um, is there a car that starts with "U"?
22. Volkswagen
Test #3: level="single",
count="chapter|sect1|sect2|sect3",
format="1.1.1.1. "
1. Alfa Romeo
1. Bentley
2. Chevrolet
1. Dodge
1. Eagle
2. Ford
1. GMC
1. Honda
1. Isuzu
2. Javelin
3. K-Car
4. Lincoln
2. Mercedes
3. Nash
1. Opel
2. Pontiac
4. Quantum
1. Rambler
2. Studebaker
2. Toyota
1. Um, is there a car that starts with "U"?
3. Volkswagen
Test #4: level="multiple",
select=".//sect2",
count="chapter|sect1|sect2",
format="I-A-i: "
I-B-i: Dodge
II-A-i: Honda
II-A-ii: Mercedes
II-A-iii: Nash
II-A-iv: Quantum
II-B-i: Um, is there a car that starts with "U"?
Test #5: level="any",
count="[various elements]"
from="[various elements]"
format="1.1.1.1. "
1.2.1.1. Eagle
2.1.1.1. Isuzu
2.1.1.2. Javelin
2.1.1.3. K-Car
2.1.1.4. Lincoln
2.1.3.1. Opel
2.1.3.2. Pontiac
2.1.4.1. Rambler
2.1.4.2. Studebaker
Test #6: level="any",
count="chapter|sect1|sect2|sect3",
grouping-separator=",",
using a variable to start counting at 1000.
1,000. Alfa Romeo
1,001. Bentley
1,002. Chevrolet
1,003. Dodge
1,004. Eagle
1,005. Ford
1,006. GMC
1,007. Honda
1,008. Isuzu
1,009. Javelin
1,010. K-Car
1,011. Lincoln
1,012. Mercedes
1,013. Nash
1,014. Opel
1,015. Pontiac
1,016. Quantum
1,017. Rambler
1,018. Studebaker
1,019. Toyota
1,020. Um, is there a car that starts with "U"?
1,021. Volkswagen
Test #7: level="multiple",
count="chapter|sect1|sect2|sect3",
format="1.1.1.1. ",
selecting up to the first two <sect1> elements from chapter 2.
2.1. GMC
2.1.1. Honda
2.1.1.1. Isuzu
2.1.1.2. Javelin
2.1.1.3. K-Car
2.1.1.4. Lincoln
2.1.2. Mercedes
2.1.3. Nash
2.1.3.1. Opel
2.1.3.2. Pontiac
2.1.4. Quantum
2.1.4.1. Rambler
2.1.4.2. Studebaker
2.2. Toyota
2.2.1. Um, is there a car that starts with "U"?
In Test 1, we used level="multiple" to count the <chapter>, <sect1>, <sect2>, and <sect3> elements. Numbering these at multiple levels gives us a dotted-decimal number for each element. We can look at the number next to Studebaker and know that it is the second <sect3> element inside the fourth <sect2> element inside the first <sect1> element inside the second <chapter> element. Test 2 uses level="any" to count all of the <chapter>, <sect1>, <sect2>, and <sect3> elements in order. Test 3 uses level="single" to count the elements at each level. This means that the fourth <sect3> element inside a given <sect2> element will be numbered with a 4 (or iv or D or whatever the appropriate value would be). Notice that the number used for each element is the same as the last number beside each element in Test 1. Test 4 does a couple of things differently: first, it uses the uppercase-alpha and lowercase-roman numbering styles. Second, it counts elements at multiple levels (for the <chapter>, <sect1>, and <sect2> elements), but we only process the <sect2> elements. Even though we only output the title text for the <sect2> elements, we can still generate the appropriate multilevel numbers. Test 5 generates numbers similarly to Test 4, except that it uses the from attribute. We generate numbers for <sect3> elements in four stages; first, we count the <chapter> ancestors, starting at the first <book> ancestor; then we count the <sect1> ancestors, starting at the first <chapter> ancestor, etc. Test 6 starts counting at 1000 instead of 1. To do this, we have to store the value generated by <xsl:number> in a variable, then output the value of the variable plus 1000. Notice that we can use an expression in the value attribute of the <xsl:number> element. We also used the grouping-separator attribute to use a comma to separate groups of three digits. Last but not least, Test 7 only numbers items from the first and second <sect1> elements (<sect1> elements whose position() is less than 3) in the second <chapter> element. Even though we're only processing these sections, we can still use <xsl:number> to generate the correct numbers for the elements. |
|