As we saw earlier, the simplest way to calculate the number that will be output
to the destination document is using the value attribute. Any expression that
can be converted to a number can be used here. A more complex, but in some cases
very powerful, way to calculate the number is using the level
,
count
and from
attributes. It is used whenever the
value
property is not used.
We will explain the workings of the number
element by example.
Imagine an XML document containing the full text of a book. The book is divided
into chapters (CH
elements), sections (SEC
elements)
and paragraphs (P
elements). Within a paragraph, we want to create
a paragraph title, including the chapter number, section number, paragraph number,
etc. These numbers are not really content; they follow from the structure of
the content. We would really like Chapter 1 to be called 'Introduction', not
'1. Introduction'. Still, in the final hardcopy (or web page or Acrobat document
etc.) we want the number to show up. So we will let the XSLT processor do the
counting and insert the numbering on the fly. This is exactly what the number
element is good at. Let's have a look at our book document:
|
level attribute
We are transforming the context node at the bottom of the diagram. There are
three modes for counting nodes, 'single
', 'multiple
'
and 'any
'. The counting mode is set using the level
attribute. The default mode is 'single
'.
level='single'
The count
attribute specifies which kind of nodes you want to
count. If the level
attribute is set to 'single
',
the processor will search along the ancestor
axis for a node that
matches the count
attribute. If the count attribute is empty, it
uses the context node itself. Once the processor has found a matching ancestor,
it counts the number of preceding siblings that also match the count
attribute and adds one. It's quite complex, right? Look at the diagram above.
Suppose we want to display the paragraph number of the paragraph our context
node is part of. That would be 2 – i.e. it is the second paragraph in the section.
To display this the following code would be used:
<xsl:number level='single' count='P'/>
The processor goes up from the context node until it finds a node that matched
'P'. Then it looks at this node's preceding siblings and counts the number of
them that match the count
attribute (1). It adds one to that, returning
2. The chapter number would similarly be returned by:
<xsl:number level='single' count='CH'/>
The from
attribute allows us to look only at a part of the ancestor
axis. If the from
attribute is specified, the processor will first
search for an ancestor that matches the from
attribute. After that,
it will search for the node that will be counted using the count
attribute, but it will not look past the node that was matched by the from
attribute. This allows you to narrow down the counting to a subtree of the document.
Using the 'multiple
' mode is very much like the 'single
'
mode, but it can return more values at once:
level='multiple'
This is useful for creating paragraph numbers like §2.2.2. The processor will
search along the ancestor
axis for all nodes matching the count
attribute. Each matching node will be used to calculate a number (just like
in single mode, counting preceding siblings). A list of numbers is returned,
in document order. Therefore this line will return a list with the current chapter
number, section number and paragraph number, in that order:
<xsl:number level='multiple' count='CH|SEC|P'/>
It is up to the number-to-string formatting attributes to output this list as an understandable format.
Note that you may run into trouble if your document structure is not as clean
as in this sample. If chapters are not siblings of each other, the numbering
will go wrong. Also, try to think about what happens if P
elements
are not only part of SEC
elements, but can also appear directly
in a CH
element. The P
elements would become siblings
to the SEC
elements and be included in the section numbering.
If the level
attribute is set to 'any
', the processor
counts all nodes matching the pattern in the count
attribute that
occur in the document before the context node (including the context node itself
and its ancestors):
level='any'
This can be used for counting the number of a certain kind of node throughout
the document (typically 'notes' and 'diagrams'). If the from
attribute
is specified, the processor searches backward from the context node for the
first node matching that specified by the from
attribute. Then
it counts all nodes matching the count
attribute between the 'from
node' and the context node.
Let's look at a few examples using the document structure from the diagram:
XSLT Element |
Number Value |
|
2 |
|
2, 2 |
|
7 |
|
11 |
|
5 |
To output numeric values as a string, the number
element specifies
a set of attributes. We will not cover all details of formatting numeric values
here. Numbering is a lot more complicated than you probably think. Ways of numbering
include the obvious ones such as Arabic numbers (1, 2, 3, …), letters (a, b,
c, …) and Roman numbers (I, II, III, …). But there are many more. Think of all
languages using other character sets. Even many languages that use normal Latin
characters use other letter orders when counting. Some languages (Hebrew, Greek)
have a special non-alphabetic order of letters especially for numbering. While
the specification more or less tries to address these issues, in this book we
will assume that you want to use one of the numbering types mentioned above,
and will refrain from using traditional Georgian numbering! If you need to use
more exotic numbering types, check if the XSLT implementation supports them.
Most implementations will not.
format attribute
The most important attribute for formatting numbers is the format
attribute. The format
attribute specifies the formatting for a
list of numeric values. The format string consists of alphanumeric parts, separated
by non-alphanumeric parts. When a list of numbers is formatted, the nth
alphanumeric part of the format is used for the nth number. If there
are more numbers than formats, the last format is used for the remaining numbers.
The default format (to be used if nothing is specified or if the specified format
is not supported by the XSLT implementation) is '1'. These are the most common
formats:
Format String |
Name |
Example |
"1" |
Arabic |
1, 2, 3, 4, … |
"I" |
Roman capitals |
I, II, III, IV, … |
"i" |
Roman lower |
i, ii, iii, iv, … |
"a" |
Alphabetic lower |
a, b, c, d, …, z, aa, ab, … |
"A" |
Alphabetic capitals |
A, B, C, D, … |
"01" |
Arabic with trailing zero |
Comments