WEEK 1 Day 4
Using Templates

Yesterday you learned how to select element attributes from Extensible Markup Language (XML) source with XPath expressions. By using these expressions when matching templates, you achieved more control over the output from a stylesheet applied to an XML source. XPath expression templates form the cornerstone of XSLT. So, now it’s time to learn more about templates and what you can do with them.

In today’s lesson covering option templates, you will learn the following:

• Why templates are so significant in XSLT

• How to work with match templates

• How to work with named templates

• What happens when more than one template matches

• How to give priorities to templates

Understanding Templates

Templates are a key concept in XSLT. If you don’t fully understand them, you cannot fully understand and utilize the power of XSLT. To make sure that you know what templates are all about and how to use them, today’s lesson is all about templates.

A Closer Look at Templates

You have already performed some tasks using templates, so by now you should understand what a template is and does. The next step is to build on the practical basics you know to get a deeper understanding of the template’s role.

Back to the Beginning

Before you move on to new topics, you need to go back to the basics described already and formalize your understanding.

A template contains a set of instructions that are executed when the template is called. These instructions are other XSLT elements. A template either can be called explicitly or can be matched based on a rule against a node in the XML document tree being processed. Explicit calls will be discussed later in this lesson.

A template can be called based on a matching node in the XML document tree if it contains a match attribute. The match attribute’s value should be an XPath expression that describes which nodes in the XML document tree the template applies to.

The fact that nodes are matched rather than selected is an important difference between XSLT and programming languages such as C, Java, and Visual Basic. When nodes are matched, they are processed as the processor encounters them in the XML document tree. This means that if two nodes matched by the same template are not in sequence, they are not processed in sequence. Any nodes in between, possibly matched by another template, are processed in between. This sequence of execution is different from most programming languages, in which you specify on which data you want to operate and then that data is processed in sequence, regardless of its position within the data store it came from. Figure 4.1 helps to illustrate this operation.

FIGURE 4.1 XML document and its tree representation.

Image

The document (and hence the document tree) in Figure 4.1 is simple. Basically, this document contains two nodes named A, with one node named B in between. Now look at Listing 4.1.

LISTING 4.1 Partial Stylesheet for Figure 4.1

1:  <xsl:template match=‘A’>
2:    <xsl:value-of select="." ?>
3:  </xsl:template>
4:
5:  <xsl:template match="B">
6:    <xsl:value-of select="." ?>
7:  </xsl:template>

ANALYSIS

Listing 4.1 is a partial listing of a stylesheet containing two templates: one matching nodes named A on line 1 and the other matching nodes named B on line 5. Because of the XML document’s structure, the output of these templates is as shown in Listing 4.2.

OUTPUT

LISTING 4.2 Output from Listing 4.1 Applied to Figure 4.1

x
z
y

ANALYSIS

Listing 4.2 is only a partial output (the stylesheet in Listing 4.1 is also only partially shown), but you can see that the first template is matched, then the second, and then the first again. The sequence these templates appear in the stylesheet doesn’t matter; the output is the same. Because XSLT is data driven, the data determines which template is executed. So, the templates are executed in the order the data appears in the XML source document, not the order in which the templates appear in the stylesheet.

Templates Explained

Elements within a template are executed in the order in which they appear in the template. The elements in the template form a structure in which the data is inserted in key places. That’s why templates are called templates; that’s what they are. Templates are there to format or reformat data, so data can be displayed in an eye-pleasing manner or transformed into another data format.

In a simplistic view, XSLT is more or less like Cascading Stylesheets (CSS). Any HTML element for which a CSS style is defined is displayed in that style—for instance, bold red text in the Verdana typeface. XSLT, however, goes much further than just applying styling information; it defines a structure in which the data is inserted. In this sense, XSLT can be better compared to a mold. In a mold, you pour a liquid that solidifies in the shape of the mold; in an XSLT template, you put data that is outputted in the shape defined by the template. The essence of the two is the same: You put in something that has no predetermined shape and can therefore be shaped into anything the material is capable of, and you get out something that is shaped the way you want it. After it is shaped, getting back the original shapeable form is probably very hard. If you transform XML into HTML, the meaning of the data gets lost in the process and is replaced by formatting data. Getting back data with even a similar meaning is very tricky, if not impossible.

The Benefit of Using Templates

XSLT is all about displaying or transforming data. If you didn’t have templates, the code for making the changes you want would probably be very long. When you use templates, this code is shortened dramatically, as the templates are reused for any node matching the match expression. The nodes matching an expression are not limited to nodes with the same names. Expressions can be very complex and match a multitude of nodes, both elements and attributes. Because you use just one expression, this is a very powerful way of reusing code. In languages such as C, Java, and Visual Basic, you would have to write a series of statements for each node type that should match and explicitly call a procedure or function to deal with it. In XSLT, the processor performs all this work for you—a further reminder that XSLT is a declarative programming language.

Targeting Multiple Documents with One Stylesheet

Using templates, you can create stylesheets that can act on many different XML documents, even if they have different structures. Being able to do so doesn’t mean that you can process all XML documents with one stylesheet, but the structure of the data in a document doesn’t necessarily have to be a one-to-one match with data from another document. The nodes that are the same in both name and structure will, however, come out the same for each document. An example will show this point clearly. Listing 4.3 shows the stylesheet you can use.

LISTING 4.3 Stylesheet Handling Different Documents

1:  <?xml version=″“1.0”" encoding="UTF-8"?>
2:  <xsl:stylesheet version=″“1.0”"
3:    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
4:
5:    <xsl:template match="/">
6:      <xsl:apply-templates />
7:    </xsl:template>
8:
9:    <xsl:template match="employee">
10:      <xsl:value-of select="@name" />
11:      <xsl:apply-templates />
12:   </xsl:template>
13:
14:   <xsl:template match="car">
15:     Manufacturer: <xsl:value-of select="@manufacturer" />
16:     Model:        <xsl:value-of select="@model" />
17:     Year:         <xsl:value-of select="@year" />
18:     Plate:        <xsl:value-of select="@plate" />
19:      <xsl:apply-templates />
20:   </xsl:template>
21:
22:    <xsl:template match="parkinglot">
23:     Parking Lot:  <xsl:value-of select="@number" />
24:   </xsl:template>
25: </xsl:stylesheet>

Note

You can download the sample listings in this lesson from the publisher’s Web site.

ANALYSIS

Listing 4.3 contains several templates, operating on different elements. The template on line 5 matches the root of the source document and immediately continues processing so that other templates are matched. The template on line 9 matches any employee element, outputs a value on line 10, and invokes templates for any child elements on line 11. The template on line 14 matching any car element is not much different but outputs several attribute values, and then on line 19 the processing is continued again. The last template on line 22 outputs only the value of the number attribute. It does not invoke other templates. Listing 4.4 shows a possible input for this stylesheet.

LISTING 4.4 Sample XML Listing to Be Used with Listing 4.3

<?xml version=″“1.0”" encoding="UTF-8"?>
<cars>
  <car model="Focus" manufacturer="Ford" year="2000" />
  <car model="Golf" manufacturer="Volkswagen" year="1999" />
  <car model="Camry" manufacturer="Toyota" year="1999" />
  <car model="Civic" manufacturer="Honda" year="2000" />
  <car model="Prizm" manufacturer="Chevrolet" year="2000" />
</cars>

ANALYSIS

Listing 4.4 shows a list of cars. Each car element has a model, manufacturer, and year attribute with different values for each element. If you apply the stylesheet in Listing 4.3 to it, the result is similar to Listing 4.5.

OUTPUT

LISTING 4.5 Result from Applying Listing 4.3 to Listing 4.4

<?xml version=″“1.0”" encoding="utf-8"?>

       Manufacturer: Ford
       Model:        Focus
       Year:         2000
       Plate:

       Manufacturer: Volkswagen
       Model:        Golf
       Year:         1999
       Plate:

       Manufacturer: Toyota
       Model:        Camry
       Year:         1999
       Plate:

       Manufacturer: Honda
       Model:        Civic
       Year:         2000
       Plate:

       Manufacturer: Chevrolet
       Model:        Prizm
       Year:         2000
       Plate:

ANALYSIS

The output from Listing 4.3 applied to Listing 4.4 is a nicely formatted list of cars. The template matching the car element is responsible for this formatting. Note that for each car in the output, no plate is listed because the elements in the source XML don’t have a plate attribute. Also, there is no output from the employee and parkinglot templates. No data matches them, so they aren’t called, and thus do not produce any output.

Listing 4.6 shows a different XML document that you can use with Listing 4.3.

LISTING 4.6 Sample XML Listing to Be Used with Listing 4.3

<?xml version=″“1.0”" encoding="UTF-8"?>
<employees>
    <employee name="Joe Dishwasher"> 
       <car model="Mustang" manufacturer="Ford" year="1981" plate="UDM988">
      <parkinglot number="17" />
       </car>
    </employee>
    <employee name="Carol Waitress">
       <car model="Metro" manufacturer="Geo" year="1997" plate="CDX236">
      <parkinglot number="7" />
       </car>
    </employee>
</employees>

ANALYSIS

The structure of the document in Listing 4.6 is different from Listing 4.4. It lists employees by name and adds information about the cars they have and which parking lot numbers they have. The car element is similar to that of Listing 4.4, but it adds an attribute for the license plate. Listing 4.7 shows the result when the stylesheet from Listing 4.3 (previously used with Listing 4.4) is used with Listing 4.6.

LISTING 4.7 Result from Applying Listing 4.3 to Listing 4.6

<?xml version=″“1.0”" encoding="utf-8"?>
    Joe Dishwasher

       Manufacturer: Ford
       Model:        Mustang
       Year:         1981
       Plate:         UDM988

       Parking Lot:  17

    Carol Waitress

       Manufacturer: Geo
       Model:        Metro
       Year:         1997
       Plate:         CDX236

       Parking Lot:  7

ANALYSIS

The result in Listing 4.7 is somewhat different. The information regarding the cars, however, is displayed in the same way in both Listings 4.5 and 4.7. The same template is matched for those elements, although the position of the car elements within the XML document is entirely different. With information added about the employees and their parking lots, the templates operating on those elements are fired and this time around produce output. Also, now that the plate attribute has been added, note that the car information in the output also contains the values of the license plates.

The preceding samples give you a good idea of how you can benefit from templates as reusable code across different data structures. The nice thing is that when you need to differentiate between the same element in differently structured data, you can. The match expressions created with XPath enable you to match with more precision if necessary, as shown in Listing 4.8.

LISTING 4.8 Partial Stylesheet with Templates Handling the Same Element with Different Parents

1:  <xsl:template match="cars/car">
2:     Manufacturer: <xsl:value-of select="@manufacturer" />
3:    Model:         <xsl:value-of select="@model" />
4:    Year:          <xsl:value-of select="@year" />
5:  </xsl:template>
6:
7:  <xsl:template match="employee/car">
8:     Manufacturer: <xsl:value-of select="@manufacturer" />
9:    Model:         <xsl:value-of select="@model" />
10:   Year:          <xsl:value-of select="@year" />
11:   Plate:         <xsl:value-of select="@plate" />
12:   <xsl:apply-templates />
13: </xsl:template>

ANALYSIS

Listing 4.8 shows two templates to replace the car template on lines 14 through 20 in Listing 4.3. These templates make a difference between car elements that are child nodes of a cars element and of an employee element. The template handling the latter hasn’t really changed, so the output would remain the same. The former, however, no longer tries to output the value of the plate attribute, so the result looks like Listing 4.9.

OUTPUT

LISTING 4.9 Result from Applying Listing 4.8 to Listing 4.4

<?xml version=″“1.0”" encoding="utf-8"?>

       Manufacturer: Ford
       Model:         Focus
       Year:         2000

       Manufacturer: Volkswagen
       Model:        Golf
       Year:         1999

       Manufacturer: Toyota
       Model:         Camry
       Year:         1999 
       Manufacturer: Honda
       Model:        Civic
       Year:          2000

       Manufacturer: Chevrolet
       Model:        Prizm
       Year:          2000

ANALYSIS

The result in Listing 4.9 is different because it no longer outputs the text Plate: with each car. Listing 4.8 no longer outputs this text, and processing of the element is stopped after the value of the year attribute is displayed. The processing stops because the template no longer uses apply-templates to invoke new templates.

Working with Ad Hoc Data

The example in the preceding section is useful if you’re working with data that is structured somewhat ad hoc. A nice example is article text or something that contains headers, quotes, keywords, and so on tagged using XML. This document is much like HTML, but the tags tell what something is, not how to display it. The example in Listing 4.10 shows part of such a document.

LISTING 4.10 Partial Document of XML Tagged Text

<analysis>
Listing 3.3 shows the value of all the child nodes of the <code>entrees</code>
node. If you remember yesterday’s lesson that is exactly right, as Listing 3.2
(line 6) asks for the value of the <code>entrees</code> node. The value of
that node contains all its descendant nodes. Getting its value yields the text
value of the <keyword>descendant</keyword> elements. This is a bit confusing,
because it looks like Listing 3.2 actually selects a node-set consisting of
all the child elements of the <code>entrees</code> node. If the
<code>entrees</code> node would also contain a text value, you would see that
this isn't true. We can however create an additional
<keyword>template</keyword> to handle the <code>dish</code> elements, as is
shown in Listing 3.4.
</analysis>

ANALYSIS

Listing 4.10 shows a section of the preceding lesson. I tagged this text to show you what I mean by ad hoc structured data.

Note

The tagging I used in Listing 4.10 is fictional. This book was created differently, but it could be done this way.

Documents like Listing 4.10 have no predetermined structure. At one point or another, the text can contain keywords, code, or other kinds of text requiring tagging. These tags can even be nested; for example, you might nest a keyword inside a piece of code. This type of document is quite different from a document with product information or one like the samples in the preceding section. Those documents have a more or less predetermined (and somewhat rigid) structure.

Besides being reusable entities, templates enable you to work with flexible data. Currently, most languages don’t have this capacity, so it is one of the key benefits of XML and XSLT.

Creating and Using Templates

So far, you’ve seen some of the benefits of using templates, even though you haven’t learned about some of the more powerful template features. The samples used to this point work with single matches and let the processor decide which template to invoke. If necessary, you can impose control over that process. The following sections look at various ways to gain more control.

More About Match Templates

You have already learned a great deal about match templates and have seen that they are powerful tools. This power mainly comes from the matching expressions you can use. The expressions used so far have been quite simple, matching only nodes of the same type. You also can create expressions that match nodes of different types. The easiest way to do so is to create two expressions and use them together in one expression.

NEW TERM

You can add two expressions together by using the | character, also known as the union operator. Listing 4.11 shows a stylesheet using the union operator.

Note

The union operator is not to be confused with the OR operator common in some languages. When you’re matching templates, their function is more or less the same, but in XSLT, it can be used in other situations in which they are not similar.

LISTING 4.11 Stylesheet with an Expression Using the Union Operator

1: <?xml version=″“1.0”" encoding="UTF-8"?>
2: <xsl:stylesheet version=″“1.0”"
3:  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
4:
5:  <xsl:template match="/">
6:   <xsl:apply-templates />
7:  </xsl:template>
8:
9:  <xsl:template match="firstname|lastname">
10:   <xsl:value-of select="." />
11:  </xsl:template>
12: </xsl:stylesheet>

ANALYSIS

The template on line 9 in Listing 4.11 operates on both the firstname and lastname elements. The expressions matching these elements are combined using the union operator. Listing 4.12 contains sample XML, and Listing 4.13 shows the result when Listing 4.11 is applied to Listing 4.12.

LISTING 4.12 Sample XML to Be Used with Listing 4.11

<?xml version="1.0" encoding="UTF-8"?>
<persons>
    <person>
       <firstname>Joe</firstname>
       <lastname>Dishwasher</lastname>
    </person>
    <person>
       <firstname>Carol</firstname>
       <lastname>Waitress</lastname>
    </person>
</persons>

OUTPUT

LISTING 4.13 Result from Applying Listing 4.11 to Listing 4.12

<?xml version=″“1.0”" encoding="utf-8"?>

       Joe
       Dishwasher

       Carol
       Waitress

ANALYSIS

The result in Listing 4.13 shows that the template matches both elements and does exactly the same with each element—outputs its value. Why is this technique useful? Well, an XML document may contain data similar to another, but named differently and possibly structured differently. The sample document in Listing 4.14 contains the same data as Listing 4.4 but is structured differently.

LISTING 4.14 XML Document with Car Information

<?xml version=″“1.0”" encoding="UTF-8"?>
<cars>
   <car>
      <model>Focus</model>
      <manufacturer>Ford</manufacturer>
      <year>2000</year>
   </car>
   <car>
      <model>Golf</model>
      <manufacturer>Volkswagen</manufacturer>
      <year>1999</year>
   </car>
   <car>
      <model>Camry</model>
      <manufacturer>Toyota</manufacturer>
      <year>1999</year>
   </car>
   <car>
      <model>Civic</model>
      <manufacturer>Honda</manufacturer>
      <year>2000</year>
   </car>
   <car>
      <model>Prizm</model>
      <manufacturer>Chevrolet</manufacturer>
      <year>2000</year>
   </car>
</cars>

ANALYSIS

In Listing 4.14 the attributes of each car element in Listing 4.4 are replaced by elements. So each car element now has only child elements. These elements have the same names and values as the attributes in Listing 4.4. The challenge is now getting (more or less) the same output from both documents by using only one style-sheet. To do so, you need to create templates that match both attributes and elements for each element/attribute name. For instance, the match expression for the model element/attribute would be model|@model, so the model attribute is treated the same as the model element.

There is one problem. For Listing 4.14, this naming technique works fine because this example consists of elements only. When xsl:apply-templates is executed, the processor matches all elements it encounters. Attributes, however, are not matched, so applying these templates to Listing 4.4 would yield an empty result because all data is stored in attributes. You therefore need to specify that attributes should also be added to the node-set that the processor tries to match. To do so, you need to add a select attribute to the xsl:apply-templates element. This attribute’s value should tell the processor which node-set to use when looking for a match. Like the match attribute of a template, the value of a select attribute is an XPath expression.

Be aware that a processor handles a template match expression and a select expression differently. As I discussed earlier, a template is matched and therefore depends on the node’s place and sequence in the source document. A select expression, on the other hand, selects a node-set. The node sequence in this case depends on the select expression defining the node-set. You used select expressions previously with the xsl:value-of element. You may remember that these expressions are somewhat awkward when a select expression yields a node-set instead of a text value. The expression has to create the value of the selected node-set. That same node-set is what you select when you’re using xsl:apply-templates. The idea is that you select the node-set that has to be matched, and then the processor takes over and starts matching each node in the node-set against the available templates. Listing 4.15 shows how you can transform Listings 4.4 and 4.14 with the same stylesheet.

LISTING 4.15 Stylesheet Operating on Listing 4.4 and Listing 4.14

1:  <?xml version=″“1.0”" encoding="UTF-8"?>
2:  <xsl:stylesheet version=″“1.0”"
3:    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
4:
5:    <xsl:template match="/">
6:     <xsl:apply-templates />
7:    </xsl:template>
8:
9:    <xsl:template match="car">
10:     <xsl:apply-templates select="*|@*" />
11:   </xsl:template>
12:
13:   <xsl:template match="model|@model">
14:     Model:     <xsl:value-of select="." />
15:   </xsl:template>
16:
17:   <xsl:template match="manufacturer|@manufacturer">
18:     Manufacturer: <xsl:value-of select="." />
19:   </xsl:template>
20:
21:   <xsl:template match="year|@year">
22:     Year:     <xsl:value-of select="." />
23:   </xsl:template>
24: </xsl:stylesheet>

ANALYSIS

Listing 4.15 produces a result similar to Listing 4.9 for both Listings 4.4 and 4.14. The templates on lines 13, 17, and 21 match either an element or an attribute (with the same name). They therefore perform the same action on the context node, making no difference between an element and an attribute. Line 10 in Listing 4.15 is very important because it tells the processor to select a node-set consisting of all the elements and attributes that are child nodes of the context node. In this case, all elements that are child elements of the car element and all attributes of the car element are part of the selected node-set. For Listing 4.4, this node-set consists solely of attributes, and for Listing 4.14, it consists solely of elements, but that makes no difference for the output.

Line 10 in Listing 4.15 contains a broad selection of all elements and attributes. You can easily limit this line to only certain elements and attributes. For instance, if you want a list of models only, you can change the value of the select expression to model|@model. This select expression selects only the child nodes that are either model elements or model attributes.

Using Named Templates

NEW TERM

Templates don’t necessarily have to be matched. They can be called directly as well, forcing the processor to execute the template. Using templates this way is much more like traditional programming in which you call a function or procedure that is to be executed. For you to be able to call a template explicitly, it must have a unique name within the stylesheet. This is why these types of templates are referred to as named templates. A named template is a template that can be called from another template, rather than being matched to a node by the processor.

You name a template by adding a name attribute with a unique identifier as its name. This identifier may contain a namespace, but if that’s the case, that namespace must be declared either in the stylesheet element or as part of the template itself.

Note

Namespaces are discussed thoroughly on Day 15, “Working with Name-spaces”, so don’t worry if you’re not familiar with them.

A big difference between match templates and named templates is that when a named template is called, the context node stays the same. With a matched template, the context node changes the moment xsl:apply-templates is used. Throughout the matching process, the context node can even change again.

Named templates are invoked using the xsl:call-template element. Which template is invoked is determined by the name attribute of xsl:call-template. The name attribute’s value must be the name of an existing template within the stylesheet. If the template doesn’t exist, an error occurs. Named and match templates do not interfere with one another. It is perfectly acceptable to have a template with a name attribute that is the same as a match attribute of another. Listing 4.16 shows an example with a named template.

LISTING 4.16 Stylesheet with Named Template and Match Templates

1: <?xml version=″“1.0”" encoding="UTF-8"?>
2: <xsl:stylesheet version=″“1.0”"
3:   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
4:
5:   <xsl:template match="/">
6:      <xsl:apply-templates />
7:   </xsl:template>
8:
9:   <xsl:template match="car">
10:   <xsl:call-template name="car" />
11:  </xsl:template>
12:
13:  <xsl:template name="car">
14:    Manufacturer: <xsl:value-of select="@manufacturer" />
15:    Model:    <xsl:value-of select="@model" />
16:    Year:     <xsl:value-of select="@year" />
17:  </xsl:template>
18: </xsl:stylesheet>

ANALYSIS

NEW TERM

Listing 4.16 contains a template matching the car element on line 9, and it also contains a template named car on line 13. The named template is called from the matched car template, at which time control is passed over to the named template without changing the context node. Hence, the xsl:value-of elements can use relative addressing and directly address the attributes of the car element without having to point to the location of those attributes. Even though the flow of control is entirely different for this stylesheet, it yields an output similar to Listing 4.9 when it is applied to Listing 4.4. The flow of control is the sequence in which commands or, in the case of XSLT, elements are executed.

Listing 4.16 is, of course, not very useful. The car element is processed by a different template that does exactly the same as match templates of earlier samples. Why are these templates useful? Well, mostly to break up complex templates into smaller units that are easier to work with.

NEW TERM

Named templates give you complete control over the flow of control. This undermines the whole idea of the data-driven nature of XSLT. However, in some cases, you might need to impose such control. One of those instances occurs when you need recursion, which happens when a function or, in the case of XSLT, a template calls itself. This is often the case when operations need to be executed several times based on some condition.

Note

On Day 17, “Using Recursion,” recursion will be discussed further.

Combining Named Templates and Match Templates

A match template and a named template can be one and the same. A template must have a match expression or a name, but can also have both. In that case, the template can be either matched or called, whichever is appropriate at that point.

Determining Which Template Is Used

In the preceding sections, you learned that you can explicitly tell the processor which template to process. You also learned that you can impose some control over which templates can be matched. But what happens when a node is matched by more than one template? When more than one template applies, their precedence rules determine which template is actually used. You can influence the precedence using priorities. You also can make different templates for different uses. You determine which template is used in which instance. In the following sections, these topics will be discussed.

Different Templates for Different Cases

You will find that in some cases you may have to go through a document more than once, each time creating different output. In these situations, you need several different templates matching the same nodes. Each template takes a different action. The problem is that the processor cannot determine which template to use in the separate instances. To ensure that the processor invokes the correct template, you can add a mode attribute to each template. The value of the mode attribute can be any name, but it needs to be different for each template matching the same node or node-set, and the same for each template to be invoked in a mode. When you xsl:apply-templates, you specify which mode to use. The processor then matches using only those templates belonging to that particular mode. Using this approach, you can ensure that each time you go through the document different tasks will be performed, as shown in Listing 4.17.

LISTING 4.17 Stylesheet Employing Modes

1: <?xml version=″“1.0”" encoding="UTF-8"?>
2: <xsl:stylesheet version=″“1.0”"
3:   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
4:
5:   <xsl:template match="/">
6:     <xsl:apply-templates mode="index" />
7:     <xsl:apply-templates mode="info" />
8:   </xsl:template>
9:
10:  <xsl:template match="car" mode="index">
11:    <xsl:value-of select="@model" />
12:  </xsl:template>
13:
14:  <xsl:template match="car" mode="info">
15:   <xsl:value-of select="@model" />
16:   Manufacturer: <xsl:value-of select="@manufacturer" />
17:    Year:         <xsl:value-of select="@year" />
18:   </xsl:template>
19: </xsl:stylesheet>

ANALYSIS

The stylesheet in Listing 4.17 contains two different modes, invoked one after another. Line 6 invokes templates using the index mode, and line 7 invokes templates using the info mode. When each mode is invoked, only the templates that are part of that particular mode are matched. This way, the document is processed twice, each time with a different mode. Line 10 defines a template that uses the index mode. This template is invoked only by line 6. The template on line 14 uses the info mode and is invoked only by line 7. Listing 4.18 shows the result of applying Listing 4.17 to Listing 4.4.

LISTING 4.18 Result from Applying Listing 4.17 to Listing 4.4

<?xml version=″“1.0”" encoding="utf-8"?>
  Focus
  Golf
  Camry
  Civic
  Prizm

  Focus
    Manufacturer: Ford
    Year:         2000
  Golf
   Manufacturer: Volkswagen
       Year:         1999
    Camry
       Manufacturer: Toyota
       Year:         1999
    Civic
       Manufacturer: Honda
       Year:         2000
    Prizm
       Manufacturer: Chevrolet
       Year:         2000

ANALYSIS

In Listing 4.18, the document from Listing 4.4 is processed twice. The first time only the car models are listed. On the second run, each car is listed by model, and the manufacturer and year are added.

Using modes is useful when you need to create a document that starts with a table of contents and also contains the entire text or all the data. For example, you see Web pages where the start of the page has a table of contents that enables you to go directly to the section of the page that you’re interested in. Modes are not necessarily restricted to the entire document. You also can use modes on just a section of a document tree. You can even change modes from one template to another. This way, you can create a complex flow of control, creating complex output.

Modes can also help you when you have different formatting for differently structured XML sources. In that case, you can create a stylesheet that detects which structure is used and then use the appropriate mode to process the document. This way, nodes that have to be processed differently for that structure are treated differently. Be aware that only templates belonging to a certain mode are matched when that mode is used. Templates that do not have a mode attribute are treated as a separate mode. This means that templates that have no mode are matched only when no mode is used.

Template Priorities

Keeping templates apart using modes is very handy, but when templates with the same mode match, you need to know which template will actually be invoked. The processor selects the actual template that is invoked by going through a series of selection steps as follows:

1. The processor selects all the templates that have a match attribute.

2. From those templates, the processor selects all templates that have the same mode as the active mode.

3. The processor selects those templates whose match expression matches the current node.

4. If more than one template has a match expression that matches the current node, the template that has the highest numerical priority is selected.

5. If more than one template is still left, the processor can report an error or use the last template that occurs in the stylesheet.

The priority in step 4 is a positive or negative number. A template’s priority can be specified explicitly. If it is not, it is calculated based on the match expression. Typically, match expressions that are more precise have a higher numerical priority. For instance, an expression using a wildcard has a lower priority than a match expression specifically matching a node. Multiple expressions added to one another using the union operator (|) are treated as separate expressions. For each expression, the priority is calculated separately. Table 4.1 shows the default priorities.

TABLE 4.1 Default Template Priorities

Image

Table 4.1 looks more complex than it is. Basically, it shows that the less specific an expression is, the lower its priority. Expressions with node tests that are outside the current axis or with predicates have a higher priority because the expression more specifically states which node is to be matched. Note that this also means that an expression such as //node () has a higher priority than an expression that specifies a child element. This prioritization is somewhat strange because the former expression actually matches any node within the document tree. This example goes against the idea that the more precise an expression is, the higher the priority will be. Listing 4.19 gives you an idea of the default priorities.

LISTING 4.19 Stylesheet Showing Default Priorities

1: <?xml version=″“1.0”" encoding="UTF-8"?>
2: <xsl:stylesheet version=″“1.0”"
3:   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
4:
5:   <xsl:template match="/">
6:<     <xsl:apply-templates />
7:   </xsl:template>
8:
9:   <xsl:template match="cars">
10:    <xsl:apply-templates />
11:  </xsl:template>
12:
13:  <xsl:template match="car">
14:    Model: <xsl:value-of select="@model" />
15:  </xsl:template>
16:
17:  <xsl:template match="*">
18:    xyz
19:  </xsl:template>
20: </xsl:stylesheet>

ANALYSIS

The template on line 17 uses a wildcard to match elements. Theoretically, it will match any element with any name. The templates on lines 9 and 13 match specific elements and should have precedence over the wildcard template. If you apply Listing 4.19 to Listing 4.4, the default priorities ensure that the template matching the car element is invoked for the car elements in Listing 4.4. If that weren’t the case, the template on line 17 using a wildcard would be invoked instead. Listing 4.20 shows the result of applying Listing 4.19 to Listing 4.4.

OUTPUT

LISTING 4.20 Result from Applying Listing 4.19 to Listing 4.4

<?xml version=″“1.0”" encoding="utf-8"?>

     Model: Focus

     Model: Golf

     Model: Camry

     Model: Civic

     Model: Prizm

ANALYSIS

In Listing 4.20, the template matching the car element is invoked for each car element in Listing 4.4. The template with the wildcard match isn’t invoked anywhere. If the listing didn’t have any priorities, the template with the wildcard would be the last template to occur in the stylesheet and hence would be the template invoked. Because of the default priority, the template matching the car element is invoked as it should be.

As your stylesheets become larger, default priorities will be more and more important. You are likely to encounter situations in which the invoked template is different from the template you thought would be invoked. In those cases, an XSLT debugger is useful because it shows which template is invoked. Getting the processor to invoke the right templates at that point may prove tricky, but don’t let the difficulty slow you down. When you gain more experience using XSLT, you will learn to avoid these situations most of the time and remedy them quickly when they do occur.

Adding Your Own Priorities

The default priorities calculated by the processor are always between -0.5 and 0.5. This leaves you free to define priorities that override the default priorities. If you define a priority, it needs to be a whole number, such as 1, 5, or 13. Specifying a priority with a value lower than -0.5 would make no sense because it would never be invoked; the default priority would always be higher.

You can specify your own priority for a template by adding a priority attribute to the xsl:template element. This attribute needs to have a value that is a positive whole number. Listing 4.21 shows a stylesheet using priorities.

LISTING 4.21 Stylesheet Using Priorities

1: <?xml version=″“1.0”" encoding="UTF-8"?>
2: <xsl:stylesheet version=″“1.0”"
3:   <xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
4:
5:   <xsl:template match="/">
6:   <xsl:apply-templates />
7:   </xsl:template>
8:
9:   <xsl:template match="cars">
10:    <xsl:apply-templates />
11:  </xsl:template>
12:
13:  <xsl:template match="car">
14:    Model: <xsl:value-of select="@model" />
15:  </xsl:template>
16:
17:  <xsl:template match="*" priority="1">
18:    xyz
19:  </xsl:template>
20: </xsl:stylesheet>

ANALYSIS

Listing 4.21 is similar to Listing 4.19 except that line 17 defines a template with a priority attribute. The value of the priority attribute is 1, so it will override any default priorities. So, even if the match expression of the other templates is more specific, the wildcard template on line 17 will be invoked. Listing 4.22 shows the result of applying Listing 4.21 to Listing 4.4.

OUTPUT

LISTING 4.22 Result from Applying Listing 4.21 to Listing 4.4

<?xml version=″“1.0”" encoding="utf-8"?>
    xyz

ANALYSIS

The output in Listing 4.22 is short because the cars element in Listing 4.4 is matched by the template on line 17 in Listing 4.21 using the wildcard match instead of the template matching the cars element specifically on line 9. Because this template doesn’t contain the xsl:apply-templates element, no further processing occurs after this template is invoked and the value xyz is written to the output.

From the example in Listing 4.22, you may think that defined priorities are not very useful. This is because of the simplicity of the XML documents and the stylesheets used so far. In more complex documents and stylesheets, priorities are more valuable—specifically in cases in which the match expressions are general and more than one template matches. If you have a specific matching template, you don’t have a problem. However, if all matching templates are quite general, you don’t know for certain which template matches a certain node. One solution would be to write expressions that are less general. However, doing so would mean writing more code for the same task because you would probably have to create more templates for that task. Therefore, priorities become useful when you have a very wide base of code reuse.

Summary

Today you learned that templates are structures that can be filled with data. Throughout a stylesheet, templates can be used as blocks of reusable code. Match expressions determine for which elements and attributes a template is used. These match expressions can be very complex, and one expression can even be the union of multiple expressions.

If more than one template matches the current node, the processor takes a series of steps to determine which template to invoke. These steps involve selecting the templates of the current mode that match the node and using the defined or calculated priority. The general rule for calculated priorities is that the more precisely an expression matches the current node, the higher the priority. Because of the way these rules work, you may have a surprise or two.

Today you also learned that you can invoke templates by calling them rather than have the processor match a template. This way, you can break up the complex code of a matched template because the context node stays the same when you call another template. A template must have a match expression or a name to be called with, but may have both.

Tomorrow you will learn how to create more complex output that can contain text with elements and attributes. This way, you can create XML documents from other XML documents and, in the process, restructure the XML.

Q&A

Q Can I create a stylesheet without templates?

A If you want something to happen in a controlled fashion, you need at least a template matching the root of the XML document. If you can create all the output from the xsl:value-of elements, that is up to you. You will learn more details about such elements in the following lessons, but because using templates is the preferred method and key to XSLT, templates have been discussed thoroughly first.

Q Can I use modes to create multiple documents?

A Just using modes is not enough to create multiple documents. You can create output with a divider and split the resulting document into more documents by using another program.

Q Can called templates have a mode?

A No. Named templates need to have a unique name within the document. Hence, differentiating between them with modes makes no sense.

Workshop

This workshop tests whether you understand all the concepts you learned today. It is helpful to know and understand the answers before starting tomorrow’s lesson. You can find the answers to the quiz questions and exercises in Appendix A.

Quiz

1. True or False: A template can have a match attribute and a name attribute.

2. True or False: A template using a wildcard expression in the current context has a higher priority than an expression targeting a specific node in the current context.

3. If xsl:apply-templates is used with a mode, will templates that have no mode be matched?

4. Why do you use a select attribute with xsl:apply-templates?

5. What is the difference between selecting nodes and matching nodes?

Exercises

1. Create a stylesheet for Listing 4.4 to display a list of models, then a list of manufacturers, and finally a list of years.

2. Create a stylesheet with the same output as Exercise 1, but for Listing 4.14. You also may change the stylesheet from the preceding exercise to handle both listings.

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

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