Instructions


We saw in the previous chapter that a stylesheet is evaluated by a process that involves identifying template rules, evaluating the instructions contained in a template rule to produce nodes, and then adding the nodes to a result tree. This section explores in more detail the instructions that can be evaluated to produce nodes in the result tree.

The content of an <xsl:template> declaration, and of various other XSLT elements, is known as a sequence constructor. Element nodes within a sequence constructor are one of three kinds: XSLT instructions, extension elements, and literal result elements. I'll describe these in the next three sections.

XSLT Instructions

An XSLT instruction is one of the following elements.

 <xsl:analyze-string> <xsl:apply-imports> <xsl:apply-templates> <xsl:attribute> <xsl:call-template> <xsl:choose> <xsl:comment> <xsl:copy> <xsl:copy-of> <xsl:element> <xsl:fallback> <xsl:for-each> <xsl:for-each-group> <xsl:if> <xsl:message> <xsl:namespace> <xsl:next-match> <xsl:number> <xsl:perform-sort> <xsl:processing-instruction> <xsl:result-document> <xsl:sequence> <xsl:text> <xsl:value-of> <xsl:variable> 

No other element in the XSLT namespace may appear directly in a sequence constructor. Other XSLT elements, for example <xsl: with-param >, <xsl:sort>, and <xsl: otherwise >, are not regarded as instructions, because they cannot appear directly in a sequence constructor-they may appear only in very specific contexts. The <xsl:param> element is anomalous as it can appear as a child of an <xsl:template> element, but it is constrained to appear before other elements, and is therefore not considered to be part of the sequence constructor. So, it is not classified as an instruction. The same is true of an <xsl:sort> element appearing within <xsl:for-each> or <xsl:for-each-group>.

The following table gives a brief introduction to the effect of each XSLT instruction.

Instruction

Effect

<xsl:analyze-string>

Applies a regular expression to a string, causing subsidiary instructions to be evaluated for each matching and nonmatching substring

<xsl:apply-imports>

Searches imported stylesheets for another template rule to apply to the context node

<xsl:apply-templates>

Selects a sequence of nodes, and for each of these nodes identifies the template rule to be used to process that node, invokes the template rule, and returns the results

<xsl:attribute>

Constructs an attribute node

<xsl:call-template>

Invokes a named template and returns its result

<xsl:choose>

Chooses one of a number of instructions to evaluate, based on boolean conditions

<xsl:comment>

Constructs a comment node

<xsl:copy>

Copies the context node. This is a shallow copy; the content of the new node is determined by the contained instructions

<xsl:copy-of>

Returns a deep copy of selected nodes or atomic values

<xsl:element>

Constructs an element node

<xsl:fallback>

Defines fallback behavior to use if a particular instruction is not available

<xsl:for-each>

Invokes the contained instructions once for each item in a sequence of items

<xsl:for-each-group>

Selects a sequence of items and divides these into groups according to specified criteria; invokes the contained instructions once for each group of items

<xsl:if>

Evaluates the contained instructions if and only if a specified condition is true

<xsl:message>

Outputs a message to a system-defined destination

<xsl:namespace>

Constructs a namespace node

<xsl:next-match>

Selects another template rule that applies to the context node, and invokes it

<xsl:number>

Generates a sequence number for the context node and formats it for output

<xsl:processing-instruction>

Constructs a processing instruction node

<xsl:perform-sort>

Selects a sequence of items and sorts them according to specified criteria

<xsl:result-document>

Constructs a document node to act as the root of a result tree, and optionally serializes it to a specified output destination

<xsl:sequence>

Produces a sequence of nodes and/or atomic values

<xsl:text>

Constructs a text node from literal text in the stylesheet, preserving whitespace

<xsl:value-of>

Constructs a text node

<xsl:variable>

Defines a local variable whose value can be accessed from other instructions within its scope

All of these XSLT instructions are explained in full detail in Chapter 5.

If an unknown element in the XSLT namespace is encountered in a sequence constructor, the action taken depends on whether forwards-compatible mode is enabled. This is discussed later on page 124.

Extension Instructions

An extension instruction is an instruction defined by the vendor or the user , as distinct from one defined in the XSLT standard. In both cases, they are recognized as extension elements because they belong to a namespace that is listed in the extension-element-prefixes attribute of the containing <xsl:stylesheet> element, or in the xsl:extension-element-prefixes attribute of the element itself, or of a containing literal result element or extension instruction.

In practice, extension instructions are more likely to be defined by vendors than by users. With XSLT 1.0, several vendors provided extension instructions to direct the stylesheet output to multiple output files (with XSLT 2.0, this is superseded by a standard facility, the <xsl:result-document> instruction). The Saxon product also provided the <saxon:group> extension element, which has been superseded by the <xsl:for-each-group> instruction in XSLT 2.0. An example of an extension that has not been superseded by any XSLT 2.0 feature is Saxon's <sql:query> element, which returns the result of performing a query on a relational database.

Not all products allow users to implement their own extension instructions, and with those that do, it may well involve some rather complex system-level programming. In practice, it is usually simpler to escape to user-written code by using extension functions, which are much easier to write. Extension functions are discussed later in this chapter, on page 129.

The following example shows an <acme:instruction> element that would be treated as a literal result element were it not for the xsl:extension-element-prefixes attribute, which turns it into an extension instruction.

  <acme:instruction   xmlns:acme="http://acme.co.jp/xslt"   xsl:extension-element-prefixes="acme"/>  

The way in which new extension instructions are implemented is not defined in the XSLT specification, and is likely to vary for each vendor. In fact, XSLT processors are not required to provide a mechanism for defining new extension elements. The only requirement is that they should recognize an extension instruction when they see one, and distinguish it from a literal result element.

What happens if a stylesheet that uses an extension instruction defined in the Xalan product (say) is processed using a different product (say Microsoft's)? If the processor encounters an extension instruction that it cannot evaluate (typically because it was invented by a different vendor), the action it must take is clearly defined in the XSLT standard: if the stylesheet author has defined an <xsl:fallback> action, it must evaluate that, otherwise it must report an error. The one thing it must not do is to treat the extension instruction as a literal result element and copy it to the result tree.

The <xsl:fallback> instruction allows you to define how an XSLT processor should deal with extension instructions it does not recognize. It is described in more detail on page 136, and full specifications are on page 271 in Chapter 5 .

Any element found in a sequence constructor that is not an XSLT instruction or an extension instruction is interpreted as a literal result element (for example, the <hr/> elements in the example discussed earlier). When the sequence constructor is evaluated, the literal result element will be copied to the result sequence.

So in effect there are two kinds of nodes in a sequence constructor: instructions and data. Instructions are obeyed according to the rules of the particular instruction, and data nodes (text nodes and literal result elements) are copied to the result sequence.

Literal result elements play an important role in the structure of a stylesheet, so the next section examines them in more detail.

Literal Result Elements

A literal result element is an element within a sequence constructor in the stylesheet that cannot be interpreted as an instruction, and which is therefore treated as data to be copied to the current output destination.

The notation I'm using here to describe literal result elements will be used extensively in Chapter 5, so it's worth explaining it.

  • The Format section explains where the element can appear in the stylesheet; it lists the permitted attributes and their meanings and defines what child elements can appear in this element, if any. For each attribute it gives the name of the attribute, states whether the attribute is mandatory or optional, gives the permitted values for the attribute, and explains how the attribute is used. It also indicates whether the attribute may be an attribute value template.

  • The Usage section explains what the element does and how it is used.

  • The Examples section gives examples of how the element is used. In some cases, especially where an element has several distinct usages, the examples are merged into the Usage section.

Format

A literal result element can have any name, provided it is not in the XSLT namespace and is not in a namespace declared to contain extension instructions.

Position

A literal result element always appears directly within a sequence constructor.

Attributes

Name

Value

Meaning

xsl:exclude-result-prefixes

(optional)

Whitespace-separated list of namespace prefixes (see the following note)

Each prefix in the list must identify a namespace that is in scope at this point in the stylesheet module. The namespace identified is not to be copied to the result tree.

xsl:extension-element-prefixes

(optional)

Whitespace-separated list of namespace prefixes (see the following note)

Each prefix in the list must identify a namespace that is in scope at this point in the stylesheet module. Elements that are a descendant of this literal result element, and whose names are in one of these identified namespaces, are treated as extension instructions rather than literal result elements.

xsl:version

(optional)

Number

The value 1.0 ‰« invokes backwards -compatible processing for this element and its descendants (see page 124). A value greater than 2.0 enables forwards-compatible processing (see page 126).

xsl:use-attribute-sets

(optional)

Whitespace-separated list of QNames identifying named <xsl:attribute-set> elements (see the following note)

The attributes defined in the named attribute sets are instantiated and copied as attributes of this literal result element in the constructed sequence.

xsl:type

(optional)

The name of a global type (simple type or complex type), which is either a built-in type such as xs:date, or a type defined in an imported schema

The constructed element in the result tree will be validated against this type definition. If it is valid, the element will be annotated with this type; if not, the transformation will fail.

xsl:validation

(optional)

One of the values strict ‰« , lax ‰« , strip ‰« , or preserve ‰«

Describes the validation action to be performed. This attribute cannot be combined with the xsl:type attribute. The value strict ‰« or lax ‰« causes the processor to look in the available schemas for an element declaration that matches the name of the literal result element, and to validate the constructed element against this declaration. Validation is described in more detail in Chapter 4.

Other attributes (optional)

Attribute value template

Any XPath expressions occurring between curly braces in the value are evaluated, and the resulting string forms the value of an attribute copied to the result sequence. Attribute Value Templates are described on page 116.

  <TD xsl:use-attribute-sets="blue italic centered"/>  

Note: Several of the attributes take the form of whitespace-separated lists. This is simply a list of names (or prefixes) in which the various names are separated by any of the XML-defined whitespace c «haracters: tab, carriage return, newline, or space. For example, you could write:

Here the names blue, italic, and centered must match the names of <xsl:attribute-set> elements elsewhere in the stylesheet.

Content

The content of a literal result element is a sequence constructor. It may thus contain XSLT instructions, extension elements, literal result elements, and/or text nodes.

Usage

The sequence constructor contained in the literal result element is evaluated, and this sequence is used to form the content of the new result element. This result element is then returned as the result of the instruction, to be combined with other items produced by sibling instructions in the stylesheet.

Consider a template body containing a single literal result element.

  <TD>Product code</TD>  

In this case a <TD> element will be written to the result tree with a child text node whose content is Product code ‰« . When the result tree is output to an XML or HTML file, it will regenerate the text as it appeared in the stylesheet-or something equivalent. There is no guarantee that it will be character-for-character identical, for example the processor may add or remove whitespace within the tags, or it may represent characters using character or entity references.

If the literal result element has content, then the content must be another sequence constructor, and this sequence constructor is itself evaluated; any nodes generated in the result sequence in the course of this process will become children of the element created from the literal result element.

For example, if the template body is:

  <TD><xsl:value-of select="."/></TD>  

then when the <TD> element is evaluated, its content will also be evaluated. The content in this case is a sequence constructor consisting of a single XSLT instruction, and the effect is that this instruction is evaluated to create a text node that will be a child of the <TD> element in the result tree. The instruction <xsl:value-of select="."> outputs the typed value of the current node in the source tree, converted to a string. So if this value is $83.99 ‰« , the result would be as follows .

  <TD>.99</TD>  

It is tempting to think of this as a sequence of three steps:

  • The <TD> start tag causes a <TD> start tag to be written to the output

  • The <xsl:value-of> element is evaluated and the result ( $83.99 ‰« ) is written to the output

  • The </TD> end tag causes a </TD> end tag to be written to the output

However, this is not a true picture of what is going on, and it is best not to think about it this way, otherwise you will start wondering, for example, how to delay writing the end tag until some condition is encountered in the input.

Important  

The transformation process writes nodes to the result tree; it does not write tags to a sequential file, The <TD> element in the stylesheet causes a <TD> element to be written to the result tree. You cannot write half a node to the tree-the start and end tags are not written as separate operations. The <TD> and </TD> tags are generated only when the result tree is serialized as XML or HTML.

Figure 3-3 helps illustrate this.

click to expand
Figure 3-3

If you do find yourself thinking about where you want tags to appear in the output, it is a good idea to draw a sketch showing the required shape of the result tree, and then think about how to write the stylesheet to produce the required nodes on the tree. Since the element in the result tree will always be produced by evaluating one sequence constructor in the stylesheet, this amounts to asking "what condition in the input tree should cause this result element to be generated?"

For example, suppose you want to generate an HTML table with five columns , arranging the <item> elements from the source XML five to a row. Then the condition in the source XML that causes an output row to be generated is an <item> element whose position is 1, 6, 11, and so on. The logic can be written:

  <xsl:template match="item[position() mod 5 = 1]">   <tr>   <xsl:for-each select="., following-sibling::item[position() lt 5]">   <td><xsl:value-of select="."/></td>   </xsl:for-each>   </tr>   </xsl:template>   <xsl:template match="item"/>  

The first template rule matches <item> elements that should appear at the start of a new row; it outputs the <tr> element, and five <td> elements corresponding to this <item> and its four following siblings. The second rule matches <item> elements that should not appear at the start of a new row, and does nothing, because these will already have been processed by the first template rule.

In XSLT 2.0 problems like this one can also be solved conveniently using the < xsl:for-each-group> instruction, which is described with examples in Chapter 5 on page 281. However, for simple cases like this, the approach shown above works just as well.

Attributes of a Literal Result Element

If the literal result element has attributes, other than the special xsl -prefixed ones in the list above, then these attributes too will be copied to the current output destination. So if the sequence constructor contains:

  <TD><IMG src="picture1.gif"/></TD>  

then the output will contain a copy of this whole structure. The outer <TD> element is copied to the result tree as before, and this time its content consists of another literal result element, the <IMG> element, which is copied to the result tree as a child of the <TD> element, along with its src attribute. This time both the stylesheet tree and the result tree take the form shown in Figure 3-4.

click to expand
Figure 3-4

If the value of an attribute of a literal result element contains curly braces ( { ‰« and } ‰« ), then it is treated as an attribute value template (discussed further in the next section). The text between the curly braces is treated as an XPath expression, and is evaluated as a string; the attribute written to the result tree contains this string in place of the expression. For example, suppose we apply the following template to the books.xml file used earlier.

  <xsl:template match="/">   <xsl:for-each select="//book">   <div id="div{position()}">   <xsl:value-of select="title"/>   </div>   </xsl:for-each>   </xsl:template>  

Because the position() function takes the values 1, 2,3, and 4, as we move through the set of books, the output will take the following form.

  <div id="div1">Sayings of the Century</div>   <div id="div2">Sword of Honour</div>   <div id="div3">Moby Dick</div>   <div id="div4">The Lord of the Rings</div>  

It is also possible to generate attributes for a literal result element by two other mechanisms:

  • The attribute can be generated by an <xsl:attribute> instruction. This instruction does not need to be textually within the content of the literal result element in the stylesheet, but attributes generated in the result sequence must appear before any child nodes (elements or children).

    The reason for this rule is to allow the XSLT processor to avoid building the result tree in memory. Many processors will serialize XML syntax directly to an output file as the nodes are generated, and the rule that attributes must be generated before child elements or text nodes ensures that this is possible. Technically, it's not the order in which the instructions are evaluated that matters (that's up to the implementation); rather, the rule is that attribute nodes in the result of evaluating a sequence constructor must appear earlier in the sequence than nodes to be used as children.

  • A collection of attributes can be generated by use of a named attribute set. The literal result element must contain an xsl:use-attribute-sets attribute that names the attribute sets to be incorporated: these names must correspond to <xsl:attribute-set> declarations at the top level of the stylesheet. The named attribute sets each contain a sequence of <xsl:attribute> instructions, and these cause attributes to be added to the generated element as if they were present directly in the content of the literal result element. Named attribute sets are useful to maintain a collection of related attributes such as font name, color , and size , which together define a style that will be used repeatedly in the output document; they are a direct parallel to the styles found in simpler languages such as CSS.

Attributes are added to the generated element node in a defined order: firstly, attributes incorporated using xsl:use-attribute-sets, then attributes present on the literal result element itself, and finally attributes added using <xsl:attribute> instructions. The significance of this sequence is that if two or more attributes with the same name are added, it is the last one that counts. It doesn't mean that they will necessarily appear in this order when the result tree is serialized.

Namespaces for a Literal Result Element

The namespace nodes of a literal result element are also copied to the result sequence of the sequence constructor. This is often the source of some confusion. The literal result element in the stylesheet will have a namespace node for every namespace declaration that is in scope: that is, every xmlns ‰« or xmlns:* ‰« attribute on the literal result element itself, or on any of its ancestor elements in the stylesheet. The only exception is that the attribute xmlns="" ‰« does not act as a namespace declaration, rather it cancels any earlier declaration for the default namespace.

With XML Namespaces 1.1, it is also possible to cancel declarations of non-default namespaces, using an attribute of the form xmlns:prefix="" ‰« . This undeclaration, if supported by the XSLT processor, ensures that the literal result element will not have a namespace node for that namespace prefix.

In the result tree, the element created from the literal result element is guaranteed to have a namespace node for every namespace node that was present on the literal result element in the stylesheet, except the following:

  • A namespace node for the XSLT namespace URI http://www.w3.org/1999/XSL/Transform will not be copied.

  • A namespace node for a namespace declared as an extension instruction namespace will not be copied. A namespace is declared as an extension instruction namespace by including its prefix in the value of the [xsl:]extension-element-prefixes attribute of the literal result element, or of any enclosing element in the stylesheet. (The attribute must be prefixed with the XSLT namespace if it appears on a literal result element, but must be unprefixed if it appears on an XSLT element.)

  • A namespace node for an excluded namespace will not be copied. A namespace is declared as an excluded namespace by including its prefix in the value of the [xsl:]exclude-result-prefixes attribute of this literal result element or of any ancestor element in the stylesheet. (Again, the attribute must be in the XSLT namespace when it appears on an element that is not in the XSLT namespace.)

These exceptions don't apply if the name of the element, or the name of one of its attributes, actually uses one of these namespaces. The system will always ensure that the namespaces used for the element and attributes in the result tree are declared, however hard you try to prevent it. If this isn't what you want, then the chances are you should be generating the element in a different namespace to start with. To achieve this, you might need to use the <xsl:element> instruction instead of using literal result elements.

Consider the following stylesheet.

  <xsl:stylesheet   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"   version="2.0"   xmlns:Date="java:java.util.Date"   >   <xsl:template match="/" xmlns="urn:acme-com:gregorian">   <date><xsl:value-of select="$today"/></date>   </xsl:template>   <xsl:param name="today" select="Date:toString(Date:new())"/>   </xsl:stylesheet>  

There are three namespaces in scope for the <date> element, namely the XSLT namespace, the namespace java:java.util.Date ‰« , and the default namespace urn:acme-com:gregorian ‰« . The XSLT namespace is not copied to the result tree, but the other two are. So, the <date> element added to the result tree is guaranteed to have these two namespaces in scope: java:java.util.Date ‰« , and urn:acme-com:gresorian ‰« .

This stylesheet uses two extension functions Date:new() ‰« and Date:toString() ‰« . This means that it will not be portable between different XSLT processors.

If the $today parameter is supplied as the value 2000-13-18 ‰« , the output would be as follows (regardless of the source document).

  <date xmlns="urn:acme-com:gregorian"   xmlns/Date="java:java.util.Date">2000-13-18</date>  

The first namespace declaration is necessary, because it defines the namespace for the element name <date>. However, you probably don't really want the xmlns:Date declaration here. It's not doing any harm, but it's not doing any good either. It's there because the XSLT processor can't tell that it's unwanted. If you want this declaration to be omitted, use the xsl:exclude-result-prefixes attribute as follows.

  <xsl:stylesheet   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"   version="2.0"   xmlns:Dates="java:java.util.Date"   >   <xsl:template match="/" xmlns="urn:acme-com:gregorian">   <date xsl:exclude-result-prefixes="Date">   <xsl:value-of select="$today"/>   </date>   </xsl:template>   <xsl:param name="today" select="Date:toString(Date:new())"/>   </xsl:stylesheet>  

The fact that an element in the result tree has a namespace node does not necessarily mean that when the result tree is written out as an XML document, the corresponding element will have a namespace declaration for that namespace. The XSLT processor is likely to omit the namespace declaration if it is redundant, in other words, if it duplicates a namespace declaration on a containing element. It can't be omitted, however, simply on the basis that it is not used. This is because namespace declarations might affect the meaning of the data in the output document in a way that the XSLT processor is unaware of. Applications are perfectly entitled to use namespace declarations to scope identifiers and names appearing in attribute values or text.

The xsl:exclude-result-prefixes attribute is used to remove namespace declarations that are unused and unwanted. It can't be used to remove the declaration of namespace prefixes that are actually used in the result tree. And it isn't used to remove duplicate namespace declarations, as most processors will do that automatically.

When an element is generated in the result tree, it doesn't automatically acquire copies of the namespace nodes attached to its parent in the result tree. Suppose your stylesheet has the following form.

  <xsl:template match="product" xmlns:p="product.uri">   <p:product>   <xsl:call-template name="generate-description"/>   </p:product>   </xsl:template>   <xsl:template name="generate-description">   <text>This product is brilliant!</text>   </xsl:template>  

There is nothing in the rules that causes the <text> element in the result tree to acquire a namespace node for the product.uri ‰« namespace. Despite this, the result of applying these two rules to a <product> element in the source document will probably look like this:

  <p:product xmlns:p="product.uri">   <text>This product is brilliant!</text>   </p:product>  

Note that in this serialized output, the namespace product.uri ‰« is in scope for the <text> element. However, in the result tree itself, the <text> element does not have a namespace node for this namespace URI. In XML 1.0, there is no way to serialize the document in a way that faithfully reflects this fact. But with XML Namespaces 1.1, the result tree can be serialized more accurately as follows.

  <p:product xmlns:p="product.uri">   <text xmlns:p="">This product is brilliant!</text>   </p:product>  

To get this serialization, your stylesheet needs to contain the following declaration.

  <xsl:output method="xml" version="1" undeclare-namespaces="yea"/>.  

In this example, the difference is unimportant. But if the <p:product> element were the envelope of a SOAP message, and the <text> element were the payload of the SOAP message, then the namespace undeclarations could be useful: the effect is that if the recipient of the SOAP message extracts the payload using another XSLT transformation, it will be in precisely its original form, not polluted with any declarations of SOAP namespaces.

For information about SOAP, see http://www.w3.org/TR/soap12-part0/

Namespace Prefixes

When a literal result element is copied to the result tree, the element name and attribute names of the new nodes in the result tree will have the same expanded name (that is, local name and namespace URI) as the corresponding nodes in the stylesheet. Usually, the names that are eventually output will also use the same namespace prefix.

There are unusual circumstances when the XSLT processor may need to change the prefix for a namespace. For example, it is possible to create two attributes that use the same namespace prefix to refer to different namespace URIs, as in the following example.

  <output>   <xsl:attribute name="out:file"   xmlns:out="http://domain-a.com/" >a</xsl:attribute>   <xsl:attribute name="out:dir"   xmlns:out="http://domain-b.com/">b</xsl:attribute   </output>  

The generated output in this case will look something like this.

  <output   out:file="a"   nsl:dir="b"   xmlns:out="http://domain-a.com/"   xmlns:nsl="http://domain-b.com/"/>  

The XSLT processor has no choice but to invent a prefix for one of the namespaces, because the supplied prefix is already in use with a different meaning. But because namespace prefixes are essentially arbitrary (it's only the URI that has any real significance) the meaning of the output file is not affected.

When namespace nodes are copied from the source or stylesheet tree to the result tree, the namespace prefix and namespace URI are both copied unchanged. When element or attribute nodes are copied, the expanded name of the element or attribute (that is, its local name and namespace URI) is always preserved, but the namespace prefix may occasionally need to be changed. If this happens, however, an extra namespace node will be added to the result tree to associate the new namespace prefix with the correct namespace URI.

Namespace Aliasing

In some circumstances, instead of changing the namespace prefix when a literal result element is copied to the result tree, it is necessary to change the namespace URI.

The most obvious situation where this arises is when the output document is itself a stylesheet. This isn't as esoteric a requirement as it may appear; generating a stylesheet can be a very useful technique. For example, if your company changes its house style to use different fonts and colors, you could write an XSLT transformation to convert all your existing stylesheets to the new standard.

When you generate a stylesheet, you will want to generate XSLT elements such as <xsl:template> in the result tree; but you can't include such elements as literal result elements in the stylesheet, because they would be mistaken for instructions. One approach is to generate these elements using the <xsl:element> instruction instead of literal result elements. But there is another way of doing it: you can include them in the stylesheet with a different namespace, and then declare in an <xsl: namespace-alias > element that the URI should be changed when the literal result element is copied to the result tree.

For more details of this mechanism, see <xsl:namespace-alias> in Chapter 5, on page 350.

Attribute Value Templates

As we've seen, an attribute value template is a special form of parameterized attribute value. There are two ways they can be used:

  • On a literal result element, an attribute value template provides a way of generating an attribute whose value is computed at runtime rather than always taking the same value, for example <td width="{$width}"> . You could achieve the same effect with the <xsl:attribute> instruction, but attribute value templates are easier to write and understand.

  • On some XSLT elements, certain attributes can be computed at runtime. For example, when sorting, instead of writing order=" ascending " ‰« or order="descending" ‰« , you could write order=" {$order}" ‰« so that the order varies, depending on a runtime parameter. Note that there are very few attributes where this facility is available. They are listed later in this section.

The term template here has nothing to do with XSLT template rules or <xsl:template> elements. Attribute value templates simply provide a notation for embedding variable components into an otherwise fixed attribute value.

An attribute value template is a string in which XPath expressions may be embedded within curly braces ( { ‰« and } ‰« ). The XPath expression is evaluated, and in general the result will be a sequence. Each item in this sequence is converted to a string, using the rules for the XPath string() function (see Chapter 10 of XPath 2.0 Programmer's Reference ). These strings are then concatenated, with a single space character inserted as a separator between each string. The resulting concatenated string is substituted into the attribute value in place of the original XPath expression and curly braces.

If backwards-compatibility mode is in use (that is, if version="1.0" ‰« is specified), then all strings after the first in the sequence are discarded; only the first string is included in the output. See the section Version Compatibility on page 123 for details.

For example, suppose you have a set of images representing an alphabet such as the following, and you want to use these to represent the first character of a paragraph of text.

click to expand

You could write a template rule to achieve this as follows (ignoring practical details such as how to deal with paragraphs that don't start with a capital letter). It uses the substring() function, which is described in Chapter 10 of XPath 2.0 Programmer's Reference .

  <xsl:template match="para">   <p><img src="fancy{substring(.,1,1)}.gif"/>   <xsl:value-of select="substring(.,2)" /></p>   </xsl:template>  

A paragraph that starts with the letter A (like this one) will cause the src attribute of the <img> element to be evaluated as img src=" fancyA.gif" ‰« , so it will be displayed in the browser as shown in Figure 3-5.

click to expand
Figure 3-5

If you want to include the characters { ‰« or } ‰« in an attribute value with their ordinary meaning, they should be doubled as {{ ‰« or }} ‰« . This is sometimes necessary when generating dynamic HTML, and it also happens often with the regex attribute of the <xsl:analyze-string> instruction, whose value is a regular expression. However, you should do this only in an attribute that is being interpreted as an attribute value template. In other attributes, curly braces have no special meaning.

Curly brackets can never be nested. You can use them only to include an XPath expression in the text of a stylesheet attribute; they cannot be used within an XPath expression itself. You can always achieve the required effect some other way; for example, instead of:

  <a href="#{id( 'A{@nr}' )}"> <!-- WRONG -->  

write:

  <a href="#{id( concat('A', @nr) )}">  

The concat() function, described in Chapter 10 of XPath 2.0 Programmer's Reference , performs concatenation of strings.

Attribute value templates cannot be used anywhere you like in the stylesheet. They can be used only for those attributes that are specifically identified as attribute value templates in the XSLT Recommendation. The following table gives a complete list of all the places you can use attribute value templates.

Element

Attributes Interpreted as Attribute Value Templates

Literal result elements

All attributes except those in the XSLT namespace

Extension elements

As defined by the specification of each extension element

<xsl:analyze-string>

regex, flags

<xsl:attribute>

name, namespace, separator

<xsl:element>

name, namespace

<xsl:for-each-group>

collation

<xsl:message>

terminate

<xsl:namespace>

name

<xsl:number>

format, lang, letter-value , ordinal, grouping-separator, grouping-size

<xsl:processing-instruction>

name

<xsl:result-document>

href

<xsl:sort>

lang, order, collation, data-type, case-order

<xsl:value-of>

separator

In all other contexts, don't even think of trying to use them because the curly braces will either be ignored, or cause an error to be reported . It can be very tempting, if you want to use <xsl:call-template> , for example, and the name of the template you want to call is in a variable, to want to write:

  <!- WRONG -->   <xsl:param name="tname"/>   <xsl:call-template name="{$tname}"/>   <!- WRONG -->  

However, you can't, because the name attribute (or any other attribute of <xsl:call-template> for that matter) of <xsl:call-template> is not in the above list of places where attribute value templates can be used.

Why are attribute value templates rationed so severely? The restrictions are there deliberately to make life easier for the XSLT processor:

  • Attribute value templates are never allowed for attributes of declarations. This ensures that the values are known before the source document is read, and are constant for each run of the stylesheet.

  • Attribute value templates are never allowed for attributes whose value is an XPath expression or a pattern. This ensures that expressions and patterns can be compiled when the stylesheet is read, and do not need to be re-parsed each time they are evaluated.

  • Attribute value templates are generally not allowed for attributes whose value is the name of another object in the stylesheet, for example a named template or a named attribute set. This ensures that references from one stylesheet object to another can be resolved once and for all when the stylesheet is first read. They are allowed, however, for names of nodes being written to the result tree.

  • Attribute value templates are not allowed for attributes interpreted by the XML parser, specifically xml:space, xml:lang, and namespace declarations ( xmlns and xmlns:prefix ). This is because the XML parser reads the value before the XSLT processor gets a chance to expand it. The xml:base attribute, when used on a literal result element, is anomalous: the value of the attribute as seen by the XML parser will be the value before any attribute-value-template expansion, while the value copied to the result tree will be the value after attribute-value-template expansion. It's therefore best to avoid using curly braces within the value of the xml:base attribute. (The xml:base attribute is defined in a separate W3C Recommendation called XML Base: see http://www.w3.org/TR/xmlbase/.)

When an XPath expression within an attribute value template is evaluated, the context is the same as for any other expression in the stylesheet. The idea of an expression having a context was introduced in Chapter 2, on page 78: it determines the meaning of constructs such as . ‰« , which refers to the context node, and position() ‰« , which refers to the context position. Variables and namespace prefixes may be used within the expression only if they are in scope at that point in the stylesheet. The context item, context position, and context size are determined from the sequence being processed in the most recent call of <xsl:apply-templates>, <xsl:for-each>, or <xsl:for-each-group>. Outside such a call (for example, while a global variable is being evaluated), the context item is set to a value supplied by the caller of the stylesheet (generally the document node of the source document), and the context position and size are set to 1 (one).

On entry to a stylesheet function defined using <xsl:function>, the context item, position, and size are undefined-trying to use their values will raise an error. The idea is that the result of a function should depend only on its explicit arguments. This principle makes it possible for the XPath processor to perform optimizations on function calls that would otherwise be very difficult.




XSLT 2.0 Programmer's Reference
NetBeansв„ў IDE Field Guide: Developing Desktop, Web, Enterprise, and Mobile Applications (2nd Edition)
ISBN: 764569090
EAN: 2147483647
Year: 2003
Pages: 324

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