<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
count The count attribute is an XPath expression that defines what should be counted. level This attribute defines what levels of the source tree should be considered when numbering elements. The three valid values for this attribute are single , multiple , and any : single Counts items at one level only. The XSLT processor goes to the first node in the ancestor-or-self axis that matches the count attribute, then counts that node plus all its preceding siblings that also match the count attribute. multiple Counts items at multiple levels. The XSLT processor looks at all ancestors of the current node and the current node itself, then it selects all of those nodes that match the count attribute. any Includes all of the current node's ancestors (as level= " multiple " does) as well as all elements in the preceding axis. In all of these cases, if the from attribute is used, the only ancestors that are examined are descendants of the nearest ancestor that matches the from attribute. In other words, with from= " h1 " , the only nodes considered for counting are those that appear under the nearest < h1 > attribute. from The from attribute is an XPath expression that defines where counting starts. For example, you can use the from attribute to say that counting should begin at the previous < h1 > element. value An expression that is converted to a number. Using this attribute is a quick way to format a number; the element < xsl:number value= " 7 " format= " i: " / > returns the string " vii: " . format The format attribute defines the format of the generated number: format= " 1 " Formats a sequence of numbers as 1 2 3 4 5 6 7 8 9 10 11 ... . format= " 01 " Formats a sequence of numbers as 01 02 03 04 ... 09 10 11 ... 99 100 101 ... . format= " a " Formats a sequence of numbers as a b c d e f ... x y z aa ab ac ... . format= " A " Formats a sequence of numbers as A B C D E F ... X Y Z AA AB AC ... . format= " i " Formats a sequence of numbers as i ii iii iv v vi vii viii ix x ... . format= " I " Formats a sequence of numbers as I II III IV V VI VII VIII IX X ... . format= " anything else " How this works is depends on the XSLT processor you're using. The XSLT specification lists several other numbering schemes (Thai digits, Katakana numbering, traditional Hebrew numbering, etc.); check your XSLT processor's documentation to see which formats it supports. If the XSLT processor doesn't support the numbering scheme you requested, the XSLT spec requires that it use format= " 1 " as the default. lang The lang attribute defines the language whose alphabet should be used. Different XSLT processors support different language values, so check the documentation of your favorite XSLT processor for more information. letter-value This attribute has the value alphabetic or traditional . There are a number of languages in which two letter-based numbering schemes are used; one assigns numeric values in alphabetic sequence, while the other uses a tradition native to that language. (Roman numerals—a letter-based numbering scheme that doesn't use an alphabetic order—are one example.) The default for this attribute is alphabetic . grouping-separator This attribute is the character that should be used between groups of digits in a generated number. The default is the comma ( , ). grouping-size This attribute defines the number of digits that appear in each group; the default is 3 .
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.