9.7. The <xsl:number> Instruction Element

The <xsl:number> element performs the traditional numbering role, which you might be accustomed to in the HTML ordered list (<ol>) or in word processor Bullets and Numbering tools. Its nine attributes are all optional, as shown in the following element model definition, and serve to nuance the format, starting number, and so on for the numbering:

<!-- Category: instruction -->
<xsl:number
level = "single" | "multiple" | "any"
count = pattern
from = pattern
value = number-expression
format = { string }
lang = { nmtoken }
letter-value = { "alphabetic" | "traditional" }
grouping-separator = { char }
grouping-size = { number } />

The <xsl:number> element can be used anywhere in a template and is always an empty element. Its output is a text node, which represents the appropriate level and respective number for the given context of the current node being numbered.

The simplest use of <xsl:number> is without attributes, using the default values which return the current node number, equal to the position of the node in its current context. Example 9-18 shows the use of an empty <xsl:number> to generate numbers for each <block> element.

Example 9-18. Using an empty <xsl:number> to generate basic numbers.
					TEMPLATE:

<xsl:template match="block">
<xsl:number/>
<xsl:text> - </xsl:text>
<xsl:value-of select="."/>
<xsl:text>
</xsl:text>
</xsl:template>

RESULT:

1 - 1st Street
2 - 2nd Street
3 - 3rd Street
1 - First Street
2 - Second Street
3 - Third Street
1 - Panorama Street
2 - Highland Plaza
3 - Hutchens Avenue
4 - Wildwood Drive
5 - Old Chimney Road
6 - Carrol Circle

The result of this template rule lists each <block> element preceded by the number of the node, generated with <xsl:number>. The numbering is essentially reset at the parent element of <block>, regardless of the type of parent. The additional formatting using <xsl:text> adds a dash and the break between lines.

More complex combinations of numbering can be accomplished using the attributes specified for <xsl:number>. Most of the attributes are directly affected by the use of the count attribute, which is used to select the nodes to be counted. Without the count attribute, the default behavior is to number only the elements with the same name as the currently selected node, matched from the template rule containing the <xsl:number> element.

9.7.1. The count Attribute of <xsl:number>

The count attribute determines which nodes will be counted in the numbering. Its value is a pattern expression, which can reference any node in the input document. This includes the root node, element nodes, text nodes, attribute nodes (although numbering is not valid for attribute nodes because they do not have a specified order in a node list), etc. The count attribute can be used to select one or more element-type names, or to select a specific subset of nodes to number, using predicates. Nodes identified in the count attribute can also be ancestors or descendants of the current node. For example:

<xsl:number count="block|thoroughfare"/>
<xsl:number count="thoroughfare[@*]"/>
<xsl:number count="block|thoroughfare[@*]"/>

These elements show different combinations of the count attribute, the first counting both <block> and <thoroughfare> elements, the second counting only <thoroughfare> elements that have an attribute, and the third a combination of the first two.

Note that although a node can be identified in the count attribute, it is not necessarily sent to the output result tree, but it is counted in the numbering. Any elements that are sent to the output result tree will reflect the numbering, including the elements not shown. In Example 9-19, we are changing our stylesheet to count both <block> and <sidestreet> elements. This will increment the numbering by including the <sidestreet> elements in the count. However, if we don't actually use the <sidestreet> in our output, the numbering will appear to skip wherever the <sidestreet> originally appeared.

Example 9-19. Output counting two element types when one is not displayed.
						TEMPLATE:

<xsl:template match="block">
<xsl:number count="block|sidestreet"/>
<xsl:text> - </xsl:text>
<xsl:value-of select="."/>
<xsl:text>
</xsl:text>
<xsl:apply-templates/>
</xsl:template>

RESULT:

2 - 1st Street
3 - 2nd Street
4 - 3rd Street
2 - First Street
3 - Second Street
4 - Third Street
1 - Panorama Street
2 - Highland Plaza
3 - Hutchens Avenue
4 - Wildwood Drive
5 - Old Chimney Road
6 - Carrol Circle

The three <sidestreet> elements from the input are counted as 1 and 5 in the first <thoroughfare>, and 1 in the second. However, since the <sidestreet>s are not being sent to the output, these numbers do not show up, but are still used in the overall count.

9.7.2. The level Attribute of <xsl:number>

The level attribute of <xsl:number> is used to stipulate which levels of numbering will be output for each object. It has three predefined values—single, multiple, and any. A value of single only outputs the number of the count for that object; for example, 1, 2, and 3. A value of multiple outputs all the numbers according to which level the object is at in the hierarchy; for example, 1, 2.1, and 2.1.1. Numbering is still reset at the parent of the current node for each level. The any value basically ignores hierarchical levels to generate a single sequence of numbers that do not reset.

9.7.2.1. The single Value for the level Attribute

The single value for the level attribute numbers each node in the matched node-set sequentially within the context of each parent node. The XSLT processor will reset the count to begin numbering with a value of 1 for each level in the hierarchy. The single value is the default setting for <xsl:number>'s level attribute, so it need not be declared. Simply invoking <xsl:number> without attributes will generate the single-level count of the current node type, as shown in Example 9-20.

9.7.2.2. The multiple Value for the level Attribute

Using level with a value of multiple numbers each node in the node-set according to the hierarchy, including the number of the parent and ancestor elements. The parent or ancestor elements to be used must be included in the count attribute for their value to be included. Nested elements of the same element-type name will also be treated as multiple values for numbering. Using the same input from Example 9-20, <xsl:number level="multiple"/> would result in a hierarchical count of <block>s, with the numbers of each level displayed, as shown in Example 9-21.

Example 9-20. Using an <xsl:number> with single-level numbering.
							INPUT:

<?xml version="1.0"?>
<block>Block 1
      <block>Child 1 of Block 1
            <block>Child 1 of Child 1 of Block 1</block>
            <block>Child 2 of Child 1 of Block 1</block>
            <block>Child 3 of Child 1 of Block 1</block>
      </block>
      <block>Child 2 of Block 1</block>
      <block>Child 3 of Block 1
            <block>Child 1 of Child 3 of Block 1</block>
            <block>Child 2 of Child 3 of Block 1</block>
            <block>Child 3 of Child 3 of Block 1</block>
       </block>
</block>

TEMPLATE:

<xsl:template match="block">
<xsl:number level="single"/>
<xsl:text> - </xsl:text>
<xsl:apply-templates/>
</xsl:template>

RESULT:

<?xml version="1.0" encoding="utf-8"?>
1 - Block 1
      1 - Child 1 of Block 1
            1 - Child 1 of Child 1 of Block 1
            2 - Child 2 of Child 1 of Block 1
            3 - Child 3 of Child 1 of Block 1

      2 - Child 2 of Block 1
      3 - Child 3 of Block 1
            1 - Child 1 of Child 3 of Block 1
            2 - Child 2 of Child 3 of Block 1
            3 - Child 3 of Child 3 of Block 1

Example 9-21. Using an <xsl:number> with multiple-level <block>s.
							TEMPLATE:

<xsl:template match="block">
<xsl:number level="multiple"/>
<xsl:text> - </xsl:text>
<xsl:apply-templates/>
</xsl:template>

RESULT:

<?xml version="1.0" encoding="utf-8"?>
1 - Block 1
      1.1 - Child 1 of Block 1
             1.1.1 - Child 1 of Child 1 of Block 1
             1.1.2 - Child 2 of Child 1 of Block 1
             1.1.3 - Child 3 of Child 1 of Block 1

      1.2 - Child 2 of Block 1
      1.3 - Child 3 of Block 1
             1.3.1 - Child 1 of Child 3 of Block 1
             1.3.2 - Child 2 of Child 3 of Block 1
             1.3.3 - Child 3 of Child 3 of Block 1

The more common use of the level attribute is when elements of different element-type names are used to number hierarchically. Example 9-22 shows multiple elements numbered using the count and level attributes.

We are using <block>s and <thoroughfare>s that contain <block>s as levels of counting. We don't want to count <thoroughfare> elements that don't have <block>s, so we use the predicate [block] on thoroughfare. Notice the use of <xsl:template match="text()"/> to suppress the output of unwanted text nodes.

9.7.2.3. The any Value for the level Attribute

Using level with a value of any numbers the nodes globally, without considering the context of the current node. With this value, it is possible to sequentially number nodes that occur at any level of the document's hierarchy. For example, using <xsl:number level="any"/> would result in a sequential count of <block>s, without resetting the number at the parent of <block>, as shown in Example 9-23.

Example 9-22. Using multiple level elements with count.
							INPUT:

<?xml version="1.0"?>
<main>
      <parkway>
            <thoroughfare>Governor Drive</thoroughfare>
            <thoroughfare name="Whitesburg Drive">
                  <sidestreet>Bob Wallace Avenue</sidestreet>
                  <block>1st Street</block>
                  <block>2nd Street</block>
                  <block>3rd Street</block>
                  <sidestreet>Woodridge Street</sidestreet>
            </thoroughfare>
            <thoroughfare name="Bankhead">
                  <sidestreet>Tollgate Road</sidestreet>
                  <block>First Street</block>
                  <block>Second Street</block>
                  <block>Third Street</block>
                  <sidestreet>Oak Drive</sidestreet>
            </thoroughfare>
      </parkway>
      <boulevard>
            <block>Panorama Street</block>
            <block>Highland Plaza</block>
            <block>Hutchens Avenue</block>
            <block>Wildwood Drive</block>
            <block>Old Chimney Road</block>
            <block>Carrol Circle</block>
      </boulevard>
</main>

STYLESHEET:

<xsl:stylesheet
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      version="1.0">
<xsl:template match="text()"/>
<xsl:template match="thoroughfare/block">
<xsl:number level="multiple"count="block|thoroughfare[block]"/>
<xsl:text> - </xsl:text>
<xsl:value-of select="text()"/>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>

RESULT:

1.1 - 1st Street
1.2 - 2nd Street
1.3 - 3rd Street
2.1 - First Street
2.2 - Second Street
2.3 - Third Street
<xsl:text> - </xsl:text>

A typical use for the any value of the level attribute is to number global elements, such as tables or figures that need to be numbered independently of the relative hierarchical position each occupies in the input XML document instance.

9.7.3. The from Attribute of <xsl:number>

The from attribute of <xsl:number> is used to identify an element (or elements) from the input document to use as the starting point for the numbering. Its value is a pattern expression that identifies specific nodes, essentially restarting the numbering at that point, instead of using the normal contextual resetting. This allows the stylesheet to reset the numbering using a different ancestor than the immediate parent. For example, the numbering for <block> resets at the parent element, which is either <thoroughfare> or <boulevard>. Using the from attribute, in combination with the level attribute set to any, we can change the starting point of the numbering to <parkway> and <boulevard>, as shown in Example 9-24.

Example 9-23. Result of using the level attribute with a value of any.
						TEMPLATE:

<xsl:template match="block">
<xsl:number level="any"/>
<xsl:text> - </xsl:text>
<xsl:value-of select="text()"/>
<xsl:text>
</xsl:text>
</xsl:template>

RESULT:

1 - 1st Street
2 - 2nd Street
3 - 3rd Street
4 - First Street
5 - Second Street
6 - Third Street
7 - Panorama Street
8 - Highland Plaza
9 - Hutchens Avenue
10 - Wildwood Drive
11 - Old Chimney Road
12 - Carrol Circle

The numbering for all the <block>s inside <thoroughfare> elements are now numbering sequentially, starting at 1, without regard to which <thoroughfare> they're in, while the <block>s inside the <boulevard> are also numbered sequentially starting at 1.

9.7.4. The value Attribute

The value attribute allows the use of a specified number, generated by an expression, for the numbering sequence. The expression contained in the value attribute is evaluated and converted to a number, rounded, and then converted to a string prior to being used. The default, if there is no value specified, is to number each node according to its position in context.For example, using <xsl:number value="position()"/> performs the same function as an empty <xsl:number> element, assuming no whitespace nodes between elements in the input document structure.

Example 9-24. Using the from attribute to reset numbering.
						TEMPLATE:

<xsl:template match="block">
<xsl:number level="any" from="parkway|boulevard"/>
<xsl:text> - </xsl:text>
<xsl:value-of select="text()"/>
<xsl:text>
</xsl:text>
</xsl:template>

RESULT:

1 - 1st Street
2 - 2nd Street
3 - 3rd Street
4 - First Street
5 - Second Street
6 - Third Street
1 - Panorama Street
2 - Highland Plaza
3 - Hutchens Avenue
4 - Wildwood Drive
5 - Old Chimney Road
6 - Carrol Circle

Using expressions in the value attribute, it is possible to extract a different value for the numbering, for example, if your numbering scheme starts with 0 instead of the default starting value of 1. Example 9-25 shows the renumbering of the <block>s in the <boulevard> to start from 0.

The numbering is now effectively changed to start at 0 instead of 1. Notice that we are using the <xsl:strip-space> element, discussed in Chapter 10, to remove any extra whitespace from our input so that the empty nodes are not counted.

Example 9-25. Using the value attribute to change the starting value of the numbering.
						STYLESHEET:

<?xml version="1.0"?>
<xsl:stylesheet
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      version="1.0">
<xsl:template match="text()"/>
<xsl:output omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="boulevard/block">
<xsl:number value="position() - 1"/>
<xsl:text> - </xsl:text>
<xsl:value-of select="."/>
<xsl:text>
</xsl:text>
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>

RESULT:

0 - Panorama Street
1 - Highland Plaza
2 - Hutchens Avenue
3 - Wildwood Drive
4 - Old Chimney Road
5 - Carrol Circle

9.7.5. The format Attribute

The format attribute is used to specify the model that will be used to represent numbering sequences in the output. The value of the format attribute is parsed and separated according to two classes of characters, either alphanumeric or non-alphanumeric. Alphanumeric characters are used as character models for the sequencing, and non-alphanumeric characters are used as punctuation or separators. Punctuation and separator characters are added to each sequence in the output in the same position they occupy in the format attribute, using the same character specified.

The format attribute can model five types of sequences: numeric, represented by 1 or 0; alphabetic lowercase, represented by a; alphabetic uppercase, represented by A; Roman numeral lowercase, represented by i; and Roman numeral uppercase, represented by I.

When using a numeric format, any combination of concurrent numbers is interpreted to be a complete number for the start of the sequence, such as 0001, which will increment as 0002, 0003, etc. Note that other digits besides 0 and 1 are allowed, but do not change the numbering sequence. So, using 9999 or 1111 will default the numbering to either 1 or 0001, depending on the processor used. The functionality of zero-padding, or zero-fill, for the format attribute is discussed in Section 9.7.5.2.

Alphabetic sequencing does not allow multiple combinations of characters, and any extra characters are ignored by the processor. Depending on the processor used, the combination “aaa” will be interpreted as the single character a, or default to 1. Any alphabetic character other than a or A may be interpreted by the processor as a separator, or default to 1, depending on the processor used.

Other sequences may be defined and supported based on processor-specific implementations, possibly to support language-specific character sequences.

9.7.5.1. Attribute Value Templates in the format Attribute

The value of the format attribute can be interpreted as an AVT (discussed in Section 6.6.1) when used with {}, allowing the sequencing format to be derived from an expression. The expression is processed based on the context of the current node and the result is converted to a string to determine the model for the sequencing. For example, the value for the format could be stored in a variable and retrieved with a variable reference, as shown in Example 9-26.

9.7.5.2. Zero-padding with the format Attribute

Especially handy is the option to pad a number with right-justified zeros, sometimes known as RJZF, or right-justified, zero-fill.[2] This enables a user to set a numerical set of spaces, which will always be filled with 0 regardless of the relative size of the actual sequential count at any given node. For instance, the format model 001 will number sequentially as 001, 002, 003, ... 010, 011, 012, etc., until 999 is reached.

[2] RJZF is used in specifications such as the Machine Readable Record format, or MARC record digital cataloguing system, used by most online library catalogs such as the Library of Congress.

Example 9-26. Using AVTs to retrieve a variable for format.
							STYLESHEET:

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
            version="1.0">
<xsl:output indent="yes"/>
<xsl:output omit-xml-declaration="yes"/>
<xsl:template match="text()"/>
<xsl:variable name="list-form" select="'1.a - '"/>
<xsl:template match="thoroughfare/block">
      <xsl:number count="block|thoroughfare[block]" level="multiple"
format="{$list-form}"/>
      <xsl:value-of select="."/>
      <xsl:text>
      </xsl:text>
</xsl:template>
</xsl:stylesheet>

RESULT:

1.a - 1st Street
1.b - 2nd Street
1.c - 3rd Street
2.a - First Street
2.b - Second Street
2.c - Third Street

9.7.6. The lang Attribute of <xsl:number>

The lang attribute is used to specify the language that is being used for numbering when the numbering is an alphabetic sequence. It accepts a two-character language value, such as “en” for English, from the ISO 639 specification, or a subcode, such as “en-US,” for specific countries defined by the ISO 3166 specification. The XML recommendation[3] suggests using lowercase prefixes, followed by uppercase suffixes, even though the value of the lang attribute is not case-sensitive.

[3] The XML recommendation can be found at http://www.w3.org/TR/REC-xml.

Using this attribute enables specific nuances of alphabetic order with languages other than English to be explicitly accommodated in <xsl:number>. If there is no language specified, the default value for the lang attribute is based on the language that is specified by the system environment or regional settings.

The value of the lang attribute can be interpreted as an attribute value template, or AVT (discussed in Section 6.6.1) when used with {}, allowing lang to be derived from an expression.

9.7.7. The letter-value Attribute

The letter-value attribute makes it possible to specify alphabetical representations of numbers. For instance, in English, Roman numerals are actually letters that are used as a sequence for numbering. When the language specified is English, however, Roman sequencing is handled with the format attribute.

If the language specified is something other than English, the traditional value for the letter-value attribute can be used to specify a letter sequencing other than alphabetic. When normal alphabetic sequencing is required for the language specified, the letter-value attribute should be specified as alphabetic. Note that this feature is implementation- and language-dependent.

The value of the letter-value attribute can also be interpreted as an AVT (discussed in Section 6.6.1) when used with {}, allowing letter-value to be derived from an expression.

9.7.8. The grouping-separator Attribute

The grouping-separator attribute makes it possible to specify the punctuation between groups of numbers. For instance, 1000 could be formatted as 1,000 with a comma, and it could also be formatted with a period as 1.000, using grouping-separator="." and grouping-size="3".

This attribute works closely with the grouping-size attribute, which serves to identify how many digits or characters a group is broken into and, accordingly, where the separating punctuation mark is to fall. The two are effectively interdependent, and if only one of either the grouping-separator or grouping-size attribute is used, then it is ignored.

The value of the grouping-separator attribute can also be interpreted as an AVT (discussed in Section 6.6.1) when used with {}, allowing grouping-separator to be derived from an expression.

9.7.9. The grouping-size Attribute

The grouping-size attribute identifies how groups of numbers are to be separated when they are displayed, using the value in the grouping-separator attribute as the separating character . For example, using a value of 3 for grouping-size results in a separation every third digit, starting from the right and working towards the left, as in the grouping in the number 1,000,000.

Using <xsl:number grouping-separator="." grouping-size="2">, we can change this number display to 1.00.00.00. Note, that when used in this context, the "." in the XPath connotation of “current node” is obviated.

The value of the grouping-size attribute can be interpreted as an AVT (discussed in Section 6.6.1) when used with {}, allowing grouping-size to be derived from an expression.

9.7.10. The <xsl:fallback> Instruction Element

The <xsl:fallback> instruction element is used to provide an alternative process when an XSLT instruction fails. The content for the <xsl:fallback> instruction is a template, and it has no attributes, as shown in the following element model definition:

<!-- Category: instruction -->
<xsl:fallback>
  <!-- Content: template -->
</xsl:fallback>

Normally, the processor signals an error if an instruction element that is not supported is used. The <xsl:fallback> instruction element catches the error and uses the instructions in the template provided instead of failing the process. If the <xsl:fallback> element is empty, the result is to output nothing. Note that this element is similar to a “catch” in some programming languages, which catches the error before it is sent through the process and redirects it to some other process. Example 9-27 demonstrates how we might use the <xsl:fallback> element with a hypothetical namespace with a prefix of go.

Example 9-27. Using the xsl:fallback element.
<go:jump>
      <!-- some instruction elements here -->
<xsl:fallback>
      <!-- some alternative instruction elements here -->
</xsl:fallback>
</go:jump>

In this example, the contents of the <xsl:fallback> will be instantiated if the <go:jump> extension element is not supported by the processor. Of course, the namespace for the extension element must be declared in the stylesheet for the processor to work. It is an error to use a prefixed extension function without declaring the namespace for that prefix, and <xsl:fallback> is not intended to catch legitimate errors.

It should also be noted that <xsl:fallback> is an instruction element and only works at the instruction level—that is, it is only effective as a part of a template rule or as a child of <xsl:template>. This means that any extension elements defined by some other namespace as top-level elements cannot be “caught” using the <xsl:fallback> element. Unsupported top-level elements are simply ignored by the processor.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset