Chapter 3. Advanced Stylesheet Concepts

CONTENTS
  •  3.1 Templates: The Building Blocks of Transformations
  •  3.2 Built-in Template Rules
  • Template

  • Template Rule

  • <xsl:template>

  • <xsl:apply-templates>

  • <xsl:call-template>

  • <xsl:value-of>

  • Built-in template rules

The main building block of an XSLT stylesheet is the template, which contains all the instructions used to process XML elements. In this chapter, we will discuss templates in general, as well as the <xsl:template> element and its components. Two closely related instruction elements, <xsl:apply-templates> and <xsl:call-template>, both used to select or call template rules, are included in this chapter, as well as <xsl:value-of>, which is used to extract a value from an expression. Additionally, we will discuss built-in template rules, the rules that kick in when a node in the input XML document is not matched.

3.1 Templates: The Building Blocks of Transformations

In the simplest sense, a template is a model. In XSLT, a template has a very specific structure, consisting of 18 instruction elements, LREs, extension elements, and text.

There are eleven elements that can contain templates: <xsl:template>, <xsl:if>, <xsl:when>, <xsl:otherwise>, <xsl:with-param>, <xsl:variable>, <xsl:param>, <xsl:element>, <xsl:copy>, <xsl:message>, and <xsl:fallback>. The most important and frequently used top-level element that can contain a template is the <xsl:template> element. This element is discussed in detail in Section 3.1.2.

template: An instrument used as a gauge or guide in bringing any piece of work to the desired shape a molecule or molecular pattern that determines the sequence in which other molecules are assembled unknown origin OED, 2000, XVII: 753)

Templates can also contain extension instruction elements if the extension elements are defined using namespaces. The namespace will control the function and application of the extension instruction element. If the namespace is not declared as a namespace in the stylesheet, the extension instruction element is treated like an LRE. Extension elements are discussed in Chapter 12.

Templates, template rules and the <xsl:template> element are all similar terms that can be a bit confusing. The <xsl:template> element is a top-level element that contains a set of instructions, collectively called the template. A template rule is a reference to the <xsl:template> element as a whole.

3.1.1 Template Processing

The XSLT stylesheet has rules that process a source tree and convert it to a result tree. The basic process associates a pattern with a template. In other words, the expression in the match statement of an <xsl:template> element is used to select nodes from the input tree. The nodes are then processed by the instructions in the template. The following list contains the sequence of processing from the XSLT specification (in italics), followed by a detailed explanation:

  1. A pattern is matched against elements in the source tree. The expression in the <xsl:template> match attribute is evaluated against the input source document. A set of nodes (node-set) is selected and passed to the template.

  2. A template is instantiated for a particular source element to create part of the result tree. This is actually a two-step process. The template is instantiated means that each instruction element in the template is processed. The template is not processed or instantiated unless the match attribute of the <xsl:template> element is successful in actually retrieving nodes from the input. When this match occurs, the template becomes active and any instructions or LREs found in the template are processed. The statement for a particular source element refers to the processing of each node in the node-set selected by the match.

    The second step, to create part of the result tree, is where the output is actually being built based on the instructions in the template.

  3. A template can contain elements that specify LRE structure. LREs become part of the result tree when the template rule is instantiated.

  4. A template can also contain elements from the XSLT namespace that are instructions for creating result tree fragments (RTFs). There are 18 possible XSLT instruction elements, the most common of which is the <xsl:apply-templates> instruction.

  5. When a template is instantiated, each instruction is executed and replaced by the RTF that it creates. The instantiation process takes each instruction and, upon its execution, places the resulting structure (RTF) in the corresponding location of the result tree. This is literally the building of the output file, instruction by instruction.

  6. Instructions can select and process descendant source elements. In addition to processing the node-set selected by the template rule, an expression can reach further down into the logical structure of the nodes in the node-set, including children and descendants. The input XML document instance's node hierarchy is available to the expressions in the instruction elements.

  7. Processing a descendant element creates an RTF by finding the applicable template rule and instantiating its template. Note that elements are only processed when they have been selected by the execution of an instruction. RTFs are created when a template rule is matched and its contents are instantiated. RTFs are "held" in memory until the actual result tree is built.

    Depending on subsequent processing and selection, RTFs are written to the output file according to their position in the result tree.

  8. The result tree is constructed by finding the template rule for the root node and instantiating its template. The result tree is the final version of the assemblage of all the RTFs that are instantiated by the templates. Since the root node (/) contains all the elements in the document, all other processing is complete when processing is finished for the root node. Because of the hierarchical nature of XML, processing the root node implies processing the entire document.

3.1.2 The <xsl:template> Top-Level Element

The most common components of XSLT stylesheets are the <xsl:template> elements. They form the series of template rules by which the nodes in the input XML document instance are matched and processed. The <xsl:template> element has several attributes, which are discussed in Section 3.1.3. The bulk of the content of an <xsl:template> element is called a template, and can consist of any combination of instruction elements, LREs, extension elements, and text. Preceding that template within an <xsl:template> element is one or more possible <xsl:param> elements, discussed in Chapter 8. The element model definition below shows the structure of the <xsl:template> element.

<!-- Category: top-level-element --> <xsl:template   match = pattern   name = qname   priority = number   mode = qname>   <!-- Content: (xsl:param*, template) --> </xsl:template> 

The <xsl:template> element uses an XPath pattern expression in its match attribute to select nodes from the input source tree, which are passed to the template for processing. The process of selecting and weeding out nodes is often the greatest effort involved in a transformation. XPath patterns expressions are discussed in Chapter 4. The attributes for <xsl:template> are discussed in the following section.

3.1.3 The <xsl:template> Attributes

The <xsl:template> has several attributes, which are all optional. The most common of these is the match attribute. There are also name, priority, and mode attributes, along with the xml:space attribute, which is not shown in the model. The following is a DTD representation of the attributes allowed for the <xsl:template> element, including the xml:space attribute. Each of these attributes is discussed in the following sections.

<!ATTLIST xsl:template   match CDATA #IMPLIED   name NMTOKEN #IMPLIED   priority NMTOKEN #IMPLIED   mode NMTOKEN #IMPLIED   xml:space (default|preserve) #IMPLIED > 
3.1.3.1 The <xsl:template> match Attribute

The match attribute on <xsl:template> contains an expression, and is used to select nodes from the input tree. The value of the expression is a pattern, or a path expression that addresses nodes. Note that variable references (discussed in Chapter 8) are not allowed in the match attribute. The following attribute model definition describes the characteristics of this attribute:

ATTRIBUTE: match CDATA #IMPLIED VALUE = pattern 

Once a node-set has been selected using the match attribute, each node in that set (also known as the current node is sent to the template for processing. If no nodes are matched, the template is not used.

The match attribute is not required when the name attribute (discussed in Section 3.1.3.2) is present.

Note

Because XML cannot control the requirement of one attribute when another is absent, both the match and name attributes are optional and will not cause a parsing error if omitted.

In order to begin working with consistent XML document input for the examples in this and the following chapters, we will introduce the notion of "Markup City." Markup City is an XML representation of a set of city streets. If you can imagine a simple city with a main street with a boulevard and blocks which turn off from it, you can represent this in XML as shown in Example 3-1.

Example 3-1 An XML representation of city streets.
<main>       <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> 

We can use <xsl:template> and match with LREs to see if the XML instance in Example 3-1 actually contains an element called boulevard, as shown in Example 3-2.

Example 3-2 Matching a <boulevard> element.
<xsl:template match="boulevard">              <p>Found a boulevard!</p> </xsl:template> 

This example shows how to determine if a match actually finds what is expected. The resulting HTML paragraph, <p>Found a boulevard!</p>, will only be sent to the output if a match actually occurs. The LRE shown here could then be replaced with real content. Using <xsl:apply-templates>, the contents of the <boulevard> elements would be output instead of the <p>Found a boulevard!</p> text. Using the same method for Example 3-3, we could find out if there are any blocks in the XML instance.

Example 3-3 Matching a <block> element.
<xsl:template match="block">              <p>Found a block!</p> </xsl:template> 

The <p>Found a block!</p> LRE is repeated for every block element found in the input XML document. Since there are six blocks in the input document, the output would be repeated six times. The first example would have only one <p>Found a boulevard!</p> result because there is only one <boulevard> in the input document.

In the absence of any instruction elements inside the <xsl:template>, the matched node-set is replaced in the output by whatever LREs are provided. This means that if both the template rules in our examples were used in the same stylesheet, the <block> elements in the <boulevard> would never be matched, because the template rule for <boulevard> would essentially erase the <block> elements. In order to understand this, consider the input, stylesheet, and output files in Example 3-4.

The processing of an XML document occurs sequentially, starting with the first element. The template rules in a stylesheet are accessed sequentially according to the hierarchy of the XML input document. The processor is effectively "walking the tree," visiting each element in the input and looking for a template rule for that element. This means that <main> is addressed first, followed by <boulevard>, and finally <block>. Since the content of <boulevard> is getting replaced by the LRE element <p>Found a boulevard!</p> in the output, the template rule for "block" is never even addressed.

Addressing of children elements is done by using <xsl:apply-templates>, discussed in Section 3.1.5. In effect, the stylesheet stops processing after a template rule is matched unless explicitly told to continue with an <xsl:apply-templates> instruction element, as shown in Example 3-5.

Example 3-4 One template can appear to "cancel out" the other.
INPUT: <?xml version="1.0"?> <main>       <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: <?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"             version="1.0"> <xsl:template match="block">               <p>Found a block!</p> </xsl:template> <xsl:template match="boulevard">              <p>Found a boulevard!</p> </xsl:template> </xsl:stylesheet> RESULT: <?xml version="1.0" encoding="utf-8"?>        <p>Found a boulevard!</p> 

Note that the order of the template rules in the stylesheet does not affect the output. Since the <boulevard> element comes before the <block> elements in the input XML, the template rule for <boulevard> is processed first, even though it appears last in the stylesheet.

Example 3-5 Using <xsl:apply-templates> to process <block> elements.
<xsl:template match="boulevard">              <p>Found a boulevard!</p>              <xsl:apply-templates/> </xsl:template> 
3.1.3.2 The <xsl:template> name Attribute

The name attribute is used to create a named template that can be "called" by an <xsl:call-template> rule. The <xsl:call-template> rule uses the value of the name to retrieve and process the contents of the <xsl:template>. The output resulting from the processing of the template is sent to the output result tree at the point where the <xsl:call-template> rule is invoked. The following attribute model definition describes the characteristics of this attribute:

ATTRIBUTE: name NMTOKEN #IMPLIED VALUE = qname 

The name attribute must be declared if there is no match attribute. They are not mutually exclusive, however. If the name attribute is present in the <xsl:template>, the match attribute is not required, although it is allowed.

The use of named templates will be addressed further in the section on <xsl:call-template> in Section 3.1.6.

3.1.3.3 The <xsl:template> priority Attribute

The priority attribute on a template is used to tell the processor whether this template rule should be selected over another, based on the value of the priority as compared to the value of the priority attributes of other template rules, if specified. Template rules can also have a default priority (or import precedence) based on several factors, such as position in the stylesheet or whether the template rule is imported or included. Import precedence and priority are covered in Chapter 7. The value of the priority attribute is a number, as shown in the following attribute model definition, and can include both positive and negative numbers:

ATTRIBUTE: priority NMTOKEN #IMPLIED VALUE = number 

The priority of an element is lower when the attribute value is negative or 0, and goes up as the number increases. Lower priority template rules are ignored in favor of higher priority template rules. For example, templates with priorities set to -2, 0, and 1 will have a selection priority order of 1, 0, and -2, -2 being the lowest priority.

This attribute is most useful when a number of possible matches for a given set of template rules is possible. The priority attribute, if specified, will resolve the conflict, stipulating which template rule is to be used. It is recommended to explicitly state priority values rather than rely on defaults, because the selection can be controlled more directly.

For instance, consider the two possible matches for a given set of template rules within the expanded Markup City shown in Example 3-6.

Example 3-6 Markup City with additional street details.
<?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 Drive">                  <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> 

Building on the previous examples, we may want to have a higher priority for the <block> replacement, depending on its context. For instance, any template rules matching on <block>s that are children of <boulevard> could always have priority over any others. In that case, as shown in Example 3-7, we might want to delete the unwanted <block>s when this condition is met.

Example 3-7 Using priority to preserve <block> children of <boulevard> elements and remove all others.
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"              version="1.0"> <xsl:template match="//boulevard/block" priority="2">              <p>Found a block!</p> </xsl:template> <xsl:template match="//block" priority="1">              <!--These blocks have been removed as unnecessary. --> </xsl:template> </xsl:stylesheet> 

The result of running this stylesheet against the Markup City XML file in Example 3-8 would be six occurrences of <p>Found a block!</p>, one for each <block> in the <boulevard>. Note that, depending on the XSLT processor you are using, the text contents of elements not addressed in the stylesheet may appear in the output. We will discuss this in Section 3.2 when discussing built-in template rules.

Example 3-8 Input, XSLT stylesheet, and output for a template using the mode attribute.
INPUT: <?xml version="1.0"?> <main>       <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="boulevard">            <xsl:apply-templates mode="X"/>            <xsl:apply-templates mode="Y"/>            <xsl:apply-templates mode="Z"/>      </xsl:template>      <xsl:template match="block" mode="X">            <p>Found block with mode X</p>      </xsl:template>      <xsl:template match="block" mode="Y">            <p>Found block with mode Y</p>      </xsl:template>      <xsl:template match="block" mode="Z">            <p>Found block with mode Z</p>      </xsl:template> </xsl:stylesheet> RESULT: output.xml <?xml version="1.0" encoding="utf-8"?>                    <p>Found block with mode X</p>                    <p>Found block with mode X</p>                    <p>Found block with mode X</p>                    <p>Found block with mode X</p>                    <p>Found block with mode X</p>                    <p>Found block with mode X</p>                    <p>Found block with mode Y</p>                    <p>Found block with mode Y</p>                    <p>Found block with mode Y</p>                    <p>Found block with mode Y</p>                    <p>Found block with mode Y</p>                    <p>Found block with mode Y</p>                    <p>Found block with mode Z</p>                    <p>Found block with mode Z</p>                    <p>Found block with mode Z</p>                    <p>Found block with mode Z</p>                    <p>Found block with mode Z</p>                    <p>Found block with mode Z</p> 
3.1.3.4 The <xsl:template> mode Attribute

The mode attribute is used in conjunction with the <xsl:apply-templates> rule. Both the <xsl:apply-templates> and <xsl:template> elements must have matching mode attributes to work together. An <xsl:apply-templates> element with a mode will search for an <xsl:template> element with the same mode and process its template. The value of a mode attribute is a number, as shown in the following attribute model definition:

ATTRIBUTE: mode NMTOKEN #IMPLIED VALUE = qname 

Because multiple template rules can be defined with different modes, the content of the template rule can be processed multiple times, once for each <xsl:apply-templates> element that is used with that particular mode.

A mode attribute on a template rule is only used when there is a match attribute as well. The mode attribute only tells the parser that the template rule has a specific condition attached to it. The match attribute still must be implemented for the proper node-set to be selected for processing. Example 3-8 uses our simplified Markup City to demonstrate.

The processor is basically reiterating over the content of the element <boulevard>, repeating the call to the template rules for <block> for each <xsl:apply-templates> element in the stylesheet.

3.1.3.5 The xml:space Attribute[1]

The xml:space attribute comes from the xml namespace and provides functionality for handling whitespace text nodes that are found in the stylesheet. Whitespace text nodes are nodes that only contain whitespace. If they contain any other characters, they are not considered. The xml:space attribute is used to set a default action for either preserving or removing whitespace nodes from all the descendant elements of the <xsl:template> element. If other elements inside the template use the xml:space attribute, they will override the value declared in this element.

The value for the xml:space attribute is a choice of either default or preserve, as shown in the following attribute model definition:

ATTRIBUTE:  xml:space (default|preserve) #IMPLIED VALUE = (default|preserve) 

It is important to note that the xml:space attribute applies only to the structure of the stylesheet, not to the structure of the input source document. The preserving or stripping of nodes from the source tree is controlled with a set of top-level elements, <xsl:strip-space> and <xsl:preserve-space>, discussed in Chapter 10.

Note

Be careful not to use this attribute on an LRE because it will be passed on to the resulting output.

3.1.4 Components of a Template

The bulk of the content of the <xsl:template> element is collectively called the template. The template consists of the 18 instruction elements, plus any LREs and extension elements that can be defined or used by the author of the stylesheet. Text is also allowed as a child of the <xsl:template> element, as noted in the following DTD representation as #PCDATA.

<!ELEMENT xsl:template  (#PCDATA   | xsl:apply-templates   | xsl:call-template   | xsl:apply-imports   | xsl:for-each   | xsl:value-of   | xsl:copy-of   | xsl:number   | xsl:choose   | xsl:if   | xsl:text   | xsl:copy   | xsl:variable   | xsl:message   | xsl:fallback   | xsl:processing-instruction   | xsl:comment   | xsl:element   | xsl:attribute   |%LRE-elements;   |%Extension-elements;   | xsl:param)* > 

There is one element that is allowed as a child of the <xsl:template> element and is not part of the template. The <xsl:param> element is a top-level element that is also allowed as a child of the template element, but is not considered an instruction element.

3.1.4.1 Instruction Elements

Instruction elements are children or descendant elements of an <xsl:template> element and provide an "instruction" to the processor concerning the node-set selected by the template rule. The term instruction element is an arbitrary categorization and does not necessarily apply to all children of the <xsl:template>. Also, some elements that are classified as instruction elements, such as <xsl:variable>, are also allowed as top-level elements. Other elements that can be children of <xsl:template> but are not classified as instruction elements are <xsl:param> and LREs. The instruction elements defined by the XSLT specification are shown in Table 3-1. The XSLT specification further subdivides instruction elements into character instruction elements, which perform specific functions on existing structures or other templates, and noncharacter instruction elements, which are used to generate XML-specific structures.

Table 3-1. Instruction elements
Character Instruction Elements
1. <xsl:apply-templates>
2. <xsl:call-template>
3. <xsl:apply-imports>
4. <xsl:for-each>
5. <xsl:value-of>
6. <xsl:copy-of>
7. <xsl:number>
8. xsl:choose>
9. <xsl:if>
10. <xsl:text>
11. <xsl:copy>
12. <xsl:variable>
13. <xsl:message>
14. <xsl:fallback>
Noncharacter Instruction Elements
15. <xsl:processing-instruction>
16. <xsl:comment>
17. <xsl:element>
18. <xsl:attribute>

User-defined instruction elements, called extension instruction elements, can be declared using namespaces and are also defined as instruction elements because they are found as elements in a template. Extension instruction elements are discussed in Chapter 12.

3.1.5 The <xsl:apply-templates> Instruction Element

The <xsl:apply-templates> element is used to process the content of an XML element that has been selected by a template rule. It is most commonly seen as an empty element, in the form of <xsl:apply-templates />. This instruction element has two attributes, and can contain two elements, as shown in the following element model definition:

<!-- Category: instruction --> <xsl:apply-templates   select = node-set-expression   mode = qname>   <!-- Content: (xsl:sort | xsl:with-param)* --> </xsl:apply-templates> 

The <xsl:sort> elements (discussed in Chapter 9) permitted within the <xsl:apply-templates> element enable the children of the selected node to be sorted. The <xsl:with-param> element (discussed in Chapter 8) enables the re-declaration of parameters that have been set elsewhere in the <xsl:param> top-level element.

There are two attributes for <xsl:apply-templates>, both of which are optional and not mutually dependent: the select and mode attributes. The select attribute can be used to "pick" nodes from the input tree for use in creating the result tree.[2] The mode attribute is used to select template rules that use the same mode. These attributes are discussed in detail in Sections 3.1.5.2 and 3.1.5.3, respectively.

3.1.5.1 Using the <xsl:apply-templates> Instruction Element

The <xsl:apply-templates> instruction element is the recursion component of XSLT. At the point where it is used in a template, the processing of the template stops to address the children of the element being processed before returning to continue the processing of the template. In this regard, it is similar to some programming concepts, such as subroutines or macros. However, the subprocessing is controlled by the structure of the XML, addressing each child of the selected, or current, node before ending the subprocess. If the child node's template rule also contains an <xsl:apply-templates> rule, the same process is followed for the children of that node.

Using <xsl:apply-templates> basically tells the processor to stop, get each child of the current node, find a template rule for it, and process it. This element can be thought of as the "process content" instruction.

When the <xsl:apply-templates> element is used without attributes, it selects the template rules for each child of the current node. In other words, if the child of the element <boulevard> is <block>, the processor will look for a template element with a match attribute of "block". If there is no such template element, the built-in template rule (discussed in Section 3.2) kicks in and basically passes the text of the <block> to the output. Example 3-9 shows a template using <xsl:apply-templates> to process the children of <boulevard>.

Example 3-9 Using <xsl:apply-templates>.
<xsl:template match="boulevard">       <xsl:apply-templates/> </xsl:template> 

A sample DTD representation of the <xsl:apply-templates> element is as follows:

<!ELEMENT xsl:apply-templates       (xsl:sort       | xsl:with-param)*> <!ATTLIST xsl:apply-templates       select CDATA #IMPLIED       mode NMTOKEN #IMPLIED > 
3.1.5.2 The <xsl:apply-templates> select Attribute

The value of the select attribute, as shown in the following attribute model definition, contains an expression that identifies a specific node or node-set. The template rules for this node-set are selected instead of processing all the children of the current node:

ATTRIBUTE: select CDATA #IMPLIED VALUE: node-set-expression 

If the select attribute is not present in the <xsl:apply-templates> element, the default action is to process all the children of the current node. The "implied" select attribute value is the element-type name of each child node being processed.

The following two template rules are essentially the same, because, in the case of Markup City, the only children of <boulevard> are <block>s.

<xsl:template match="boulevard">       <xsl:apply-templates select="block"/> </xsl:template> <xsl:template match="boulevard">       <xsl:apply-templates/> </xsl:template> 

If there were other element-type children of <boulevard>, the <xsl:apply-templates> rule for the first "boulevard" would not match those children, but the second would. In both cases, the <xsl:apply-templates> rule would look for a template rule matching <block>.

Using the select attribute, it is possible to explicitly select a subset of children nodes, or even a group of nodes completely different than the children of the current node. The interesting concept here is that the select attribute is not limited to selecting from the nodes that are children of the current node. The select can go outside the current node and select any element within the entire structure of the input document. Example 3-10 demonstrates this using the expanded Markup City for input.

Example 3-10 Using the select attribute to process elements other than children
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 Drive">                      <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> TEMPLATE RULE: <xsl:template match="boulevard">            <p>            <xsl:apply-templates select="//thoroughfare/sidestreet"/>            </p> </xsl:template> RESULT: <p>Bob Wallace Avenue Woodridge Street Tollgate Road Oak Drive</p> 

This template rule starts at the <boulevard> (the current node matched by the <xsl:template> element) and moves outside the <boulevard> using an "absolute path" to find any occurrence of any <sidestreet> in a <thoroughfare> anywhere in the document (indicated by the //). Each <sidestreet> is processed and the result replaces the contents of the children of the <boulevard> in the output result tree, surrounded by <p> tags. Note that suppressing the original content of the thoroughfare and adding the break between sidestreet names are accomplished by other template rules not shown here. The same result can be accomplished by using a more convenient "relative path" expression if the location of the <sidestreet> is known in relation to the <boulevard>, as shown in Example 3-11. Absolute and relative paths are discussed further in Chapter 4.

Example 3-11 Use of a relative path expression in the select attribute of <xsl:apply-template>.
<xsl:template match="boulevard">       <p>              <xsl:apply-templates select="../parkway/thoroughfare/sidestreet"/>       </p> </xsl:template> 

Of course, the more common use of a select attribute is to distinguish between the children nodes of the current node and select one set over the others for processing, as shown in Example 3-12.

Example 3-12 A simple node selection in the select attribute of <xsl:apply-templates>.
<xsl:template match="main">       <p>              <xsl:apply-templates select="boulevard"/>       </p> </xsl:template> 

In this case, the // is not required because the <boulevard> is a child of the <main> element. This expression would ignore the <parkway> child and process only the <boulevard>.

As mentioned previously, when the select attribute is omitted from the <xsl:apply-templates> element, the default action is to process all the children of the current node, as shown in Example 3-13.

Example 3-13 A basic template which processes the children of the main element.
<xsl:template match="main">       <xsl:apply-templates /> </xsl:template> 

The <xsl:apply-templates> would process both <parkway> and <boulevard> elements because that is the node-set that consists of the children of the <main> element.

Note

When this template rule is the only rule in a stylesheet, the entire document is processed because there are built-in template rules that affect the output unless they are specifically overridden with other template rules. Built-in template rules are covered in Section 3.2.

3.1.5.3 The <xsl:apply-templates> mode Attribute

The mode attribute of <xsl:apply-templates> is used to qualify the selection of the template rules that are to be used to process the children of the current node. This attribute is used in conjunction with the same mode attribute on the <xsl:template> rule. Both the <xsl:apply-templates> and the <xsl:template> elements must have matching mode attributes to work together. The value of the mode attribute is a QName, as shown in the following attribute model definition:

ATTRIBUTE: mode NMTOKEN #IMPLIED VALUE: qname 

An <xsl:apply-templates> element with a mode will search for an <xsl:template> element with the same mode and process its content template. Template rules that do not have a matching mode attribute are ignored.

The template rule that is selected must also match the select attribute on the <xsl:apply-templates> rule when the select attribute is used. When a select attribute is used in conjunction with the mode attribute, the <xsl:apply-templates> instruction will find the <xsl:template> element with the same value in the match attribute, as well as the matching mode attribute. The stylesheet in Example 3-14 contains rules for several different elements.

Example 3-14 Using mode with select in the <xsl:apply-templates> and <xsl:template> elements.
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"            version="1.0" >      <xsl:template match="boulevard">            <xsl:apply-templates select="block" mode="X"/>      </xsl:template>      <xsl:template match="sidestreet" mode="X">            <p>Found sidestreet with mode X</p>      </xsl:template>      <xsl:template match="block" mode="X">            <p>Found block with mode X</p>      </xsl:template>      <xsl:template match="block">            <p>Found block without mode</p>      </xsl:template> </xsl:stylesheet> 

In this case, the <xsl:apply-templates> in the first template rule will only select the template rule with the equivalent match and mode attributes.

<xsl:template match="block" mode="X">       <p>Found block with mode X</p> </xsl:template> 

The result will be <p>Found block with mode X</p> for each <block> element found in the <boulevard>, and <p>Found block without mode</p> for all other <block> elements.

3.1.6 The <xsl:call-template> Instruction Element

The <xsl:call-template> element allows you to use other templates within the context of the template that is being processed. The template being called must have a name, declared with the name attribute on the <xsl:template> element. This functionality is similar to programming subprocesses that suspend the current process while another process is run. The current template rule stops, gets the template being called, and processes its content. Then, normal processing of the original template rule continues. The <xsl:call-template> element can contain an <xsl:with-param> element, as shown in the following element model definition:

<!-- Category: instruction --> <xsl:call-template   name = qname>   <!-- Content: xsl:with-param* --> </xsl:call-template> 

The <xsl:call-template> element is very useful for storing element rules and LREs that will be used by several different elements. For example, you may want a specific HTML format to be applied to all <block> and <sidestreet> elements. If the formatting was very lengthy, it would be convenient to store it all in one place, especially for maintenance purposes. Example 3-15 shows templates used to format a table row and a table cell.

Example 3-15 Templates to format a table row and cell.
<<xsl:template name="table-row">        <tr>              <xsl:apply-templates/>        </tr> </xsl:template> <xsl:template name="table-cell">        <td>              <xsl:apply-templates/>        </td> </xsl:template> 

Notice that these template rules do not apply directly to any element in our Markup City sample, but they can still be used. Example 3-16 shows a stylesheet that calls these two templates.

This example, while lengthy, simply applies a table format to our Markup City. Each <block> and <sidestreet> is formatted as a table cell, and each <boulevard> and <thoroughfare> is formatted as a table row. The main structure for the table is generated in the template rule for <main>. Instead of having repeated formatting structures in each similar element, we place them in a named template and use <xsl:call-template> to send the structure to the output. Notice how the structure of the named templates provides the recursion for the "calling" templates with <xsl:apply-templates>. Figure 3-1 shows the HTML-formatted view resulting from processing this stylesheet with the Markup City XML input.

Figure 3-1. HTML file resulting from <xsl:call-template> stylesheet.

graphics/03fig01.gif

Notice that the text content of an element (Governor Drive) gets processed even though there is no matching element rule that specifically calls for text to be sent to the output. This is being done by the built-in template rules, which will be discussed in Section 3.2. The <thoroughfare> that contains Governor Drive does not contain any <block> or <sidestreet> elements; therefore, the resulting HTML structure does not contain any <td> elements.

Example 3-16 Stylesheet using <xsl:call-template>.
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"             version="1.0">      <xsl:template match="//block" >             <xsl:call-template name="table-cell"/>      </xsl:template>      <xsl:template match="//boulevard">             <xsl:call-template name="table-row"/>      </xsl:template>      <xsl:template match="//thoroughfare">             <xsl:call-template name="table-row"/>      </xsl:template>      <xsl:template match="//sidestreet">             <xsl:call-template name="table-cell"/>      </xsl:template>      <xsl:template match="//main">             <table border="1">                    <xsl:apply-templates/>             </table>      </xsl:template>      <xsl:template match="/">             <html>             <head><title>Table Example</title>             </head>             <body>                    <xsl:apply-templates/>             </body>             </html>      </xsl:template> <xsl:template name="table-row">        <tr>        <xsl:apply-templates/>        </tr> </xsl:template> <xsl:template name="table-cell">        <td>        <xsl:apply-templates/>        </td> </xsl:template> </xsl:stylesheet> 
3.1.6.1 Current Node Processing with <xsl:call-template>

The match attribute on <xsl:template> selects a list of nodes, called the node-set, or current node list, from the nodes in the input XML document. Each of these nodes is applied individually to the template as the "current node." When a template is instantiated, the processor keeps track of the "current node" during its evaluation of further instructions. The <xsl:call-template> element does not change this basic processing rule. The current node that is being processed is used as the current node for the called template, regardless if there is a match attribute on the template being called by <xsl:call-template>. For example, consider the two template rules shown in Example 3-17.

The resulting output for each <sidestreet> is <sidestreet>sidestreet</sidestreet>, but the resulting output for the <block> element is the content of the template rule for "block" as well as the content of the template rule for "sidestreet," as if it was inside the template rule for block.

<block><sidestreet>block</sidestreet></block> 
Example 3-17 Two templates using different current nodes.
<xsl:template name="sidestreet" match="sidestreet">        <sidestreet>               <xsl:value-of select="name()"/>        </sidestreet> </xsl:template> <xsl:template match="block">        <block>               <xsl:call-template name="sidestreet"/>        </block> </xsl:template> 

Notice that the first template rule for <sidestreet> is pulling the name of the element using the name() function, which is discussed further in Chapter 5. When used in the context of the <xsl:call-template> element, the <xsl:value-of select="name()"/> returns the name of the <block> element, not the name of the <sidestreet> element, because the current node in this case is "block."

3.1.7 The <xsl:value-of> Instruction Element

A very common and useful instruction element is <xsl:value-of>, which extracts the value, or "contents," of a node identified in its select attribute. It is an empty element and contains two attributes: the mandatory select attribute and the optional disable-output-escaping, as indicated in the following element model definition:

<!-- Category: instruction --> <xsl:value-of   select = string-expression   disable-output-escaping = "yes" | "no" /> 

Because this is an empty element, the only functionality it provides is accessed through the select attribute, which supplies an expression to be evaluated. The second optional attribute, disable-output-escaping, specifically addresses the handling of certain XML character entities. These attributes are further discussed in the following sections. A DTD representation of the content model and attributes of <xsl:value-of> are as follows:

<!ELEMENT xsl:value-of EMPTY> <!ATTLIST xsl:value-of   select %expr; #REQUIRED   disable-output-escaping (yes|no) "no" > 
3.1.7.1 The <xsl:value-of> select Attribute

The select attribute of <xsl:value-of>, shown in the following attribute model definition, is used to define a string expression that is evaluated by the processor:

ATTRIBUTE: select CDATA #REQUIRED VALUE: string-expression 

The result of the evaluation can be any of the four possible function return types of expressions, node-set, string, Boolean, or number, which are discussed in Chapter 5, but the result is always converted to a string.

For example, when the result of the expression in the select attribute is a node-set, the <xsl:value-of> instruction element returns the text value of the content of the node. If the result of the evaluation of the expression in the match attribute is a Boolean, the <xsl:value-of> element returns a string of either "true" or "false." For example, <xsl:value-of select="name()"/> used in Example 3-21 evaluates the expression "name()" according to the current node and returns either "block" or "sidestreet." Additional examples of <xsl:value-of> are shown in Chapter 5 when evaluating other functions.

3.1.7.2 The <xsl:value-of> disable- output-escaping Attribute

The disable-output-escaping attribute is an optional attribute that requires some special attention. The first point that should be mentioned is that this is one of the most commonly misunderstood XSLT attributes. The fact is that disable-output-escaping applies only to five predefined entities &amp;, &lt;, &gt;, &quot;, and &apos; which resolve to &, <, >, ", and ', respectively. The disable-output-escaping attribute does not apply to any other character, including hexadecimal character entities, such as &#160; for creating a space.

The second point to mention is that output escaping is affected by the output method, whether selected by default as XML, or explicitly using <xsl:output>, discussed in Chapter 10. The default behavior for XML is to escape these characters in the output.

Escaped entities are entities that have the preceding ampersand (&) and following semi-colon (;). When the value of disable-output-escaping is set to no, the entities remain escaped. In other words, a value of "no" keeps &amp; as &amp; instead of resolving it to & in the output.

When the value of disable-output-escaping is set to yes, the resulting output is the resolved character, regardless of output method.

The attribute model definition for disable-output-escaping is as follows:

ATTRIBUTE: disable-output-escaping (yes|no) "no" VALUE: (yes|no) 

The confusion of this seemingly double negative can be avoided by remembering that these character entities will always remain character entities in XML unless this attribute is set to yes. Because the default value is no, the only time you would ever use this attribute is to force the entities to be resolved. In all cases,"disable-output-escaping" means "resolve entities for the five specific entities."

3.2 Built-in Template Rules

Template rules use the match attribute to select nodes from the input XML document to be processed. However, XSLT provides a mechanism to handle nodes that are not explicitly addressed, using the built-in template rule. The processor implements built-in template rules automatically.

There are built-in template rules for all node types; however, not all built-in templates generate output. The built-in template for the root node and element nodes simply processes the children of each node, using <xsl:apply-templates> as shown in Example 3-18.

Example 3-18 Built-in template rule for root and element nodes.
<xsl:template match="*|/">   <xsl:apply-templates/> </xsl:template> 

The built-in template for text and attribute nodes will send the contents of the node to the output tree as a string of text, and can be represented as shown in Example 3-19. However, most processors will not send the contents of an attribute to the output unless there is an explicit rule to make it happen.

Example 3-19 Built-in template rule for text and attribute nodes.
<xsl:template match="text()|@*">   <xsl:value-of select="."/> </xsl:template> 

The built-in template rules for processing-instructions, comments, and namespaces do nothing, effectively ignoring the nodes. The rules for processing-instructions and comments can be represented as an empty element, shown in Example 3-20. However, there is no way to represent a namespace pattern match, so there is no example built-in template rule for namespaces.

Example 3-20 Built-in template rule for processing-instruction and comment nodes.
<xsl:template match="processing-instruction()|comment()"/> 

The built-in template rules are treated just like other template rules, however they have a lower priority and import precedence than all other template rules. Explicit template rules always override built-in template rules for the same match pattern.

When a stylesheet has templates that use the mode attribute, as discussed in Section 3.1.3.4, the built-in template rule for modes is invoked. This template rule allows the processing for each mode to continue, even if the node is not explicitly selected by a template rule with that mode. The built-in template rule for modes applies to the root node and any element nodes that are processed with a mode attribute, as shown in Example 3-21.

Example 3-21 Built-in template rule for modes.
<xsl:template match="*|/" mode="modeA">       <xsl:apply-templates mode="modeA"/> </xsl:template> 

It is important to remember that built-in template rules exist, because the result of processing an XML document is directly affected by these rules when nodes are not explicitly matched. For example, using a very basic stylesheet, as shown in Example 3-22, the built-in template rules apply to all nodes, even though the only explicit match is on the root node.

Example 3-22 Using built-in template rules.
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"            version="1.0"> <xsl:template match="/">            <xsl:apply-templates/> </xsl:template> </xsl:stylesheet> 

The content of each element is specifically processed by the <xsl:apply-templates> in the built-in template rule for elements, down to the text level, where the text is then passed to the output with the built-in template rule for text.

[1] The xml:space attribute is not specifically shown in the content model for this element in the XSLT specification, but it is referenced later in the appendixes.

[2] If we wanted to be sticklers about the "tree" metaphor, we could say that this element does the "grafting," but that would be going a bit far afield with the common terminology used for XML document instances.

CONTENTS


XSLT and XPATH(c) A Guide to XML Transformations
XSLT and XPATH: A Guide to XML Transformations
ISBN: 0130404462
EAN: 2147483647
Year: 2005
Pages: 18

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net