The Syntax of Patterns


The rest of this chapter gives the detailed syntax rules for patterns.

The indented hierarchy that follows shows the overall structure of the rules. Constructs marked with the symbol § are defined in XPath 2.0 Programmer's Reference.

 Pattern      PathPattern         RelativePathPattern            PatternStep               PatternAxis               NodeTest               Predicates                  Expr          IdKeyPattern            Literal             VariableReference 

The rules are presented in top-down order, starting with the Pattern construct itself.

The production rules use the same syntax notation that is used to define the syntax of XPath expressions in XPath 2.0 Programmer's Reference. The entry for each construct defines the syntax using a BNF notation, it describes the meaning of the construct in a section headed Effect, and then includes sections relating to the Usage of the construct, followed by Examples. The BNF uses chevrons to enclose literal symbols, but is otherwise conventional: alternatives are indicated using « » , repetition by «* » , and optional constructs by «? » .

Pattern

This is the top-level construct for the XSLT Pattern syntax. A pattern defines a condition that is either true or false for any given node in a document. The syntax for a Pattern is a subset of the syntax for a UnionExpr (and therefore for an Expr ) in the XPath expression syntax.

Syntax

Expression

Syntax

Pattern

PathPattern \

Pattern « » PathPattern

A Pattern is either a PathPattern or a sequence of PathPatterns separated by the union operator « » .

The syntax of a PathPattern is given on the next page.

Effect

A node matches a Pattern if it matches any of the PathPatterns contained in the Pattern .

Usage

Although « » is technically a union operator, it is simpler to read it as «or »; a node matches the pattern "A B" if it matches either A or B or both.

In patterns, the « » operator can be used only at the top level. XPath 2.0 allows expressions such as «(chap)appendix)/title » , but this is not a valid pattern. The required effect can be achieved by writing «chap/title appendix/title » , or «title[parent::chap parent::appendix] » .

Examples

TITLE

«TITLE » is a PathPattern , so it is also a Pattern

preface chapter appendix

A node matches this pattern if it is a <preface> element, a <chapter> element, or an <appendix> element

/*

A node matches this pattern if it is either a document node or an element node

PathPattern

A PathPattern states conditions that a node must satisfy based on its name , its node kind, its position relative to other nodes, and/or its ID and key values.

This construct is a subset of the PathExpr construct in the XPath grammar.

Syntax

Expression

Syntax

PathPattern

 RelativePathPattern / RelativePathPattern? // RelativePathPattern IdKeyPattern ((///) RelativePathPattern)? 

This production rule is the way the syntax is defined in the XSLT specification. However, the following equivalent production rule may be easier to understand, and corresponds with the description in the Usage section discussed later.

Expression

Syntax

PathPattern

 / RelativePathPattern / RelativePathPattern // RelativePathPattern IdKeyPattern IdKeyPattern / RelativePathPattern IdKeyPattern // RelativePathPattern 

The syntax of a RelativePathPattern (page 505) and that of an IdKeyPattern (page 518) are described later.

Effect

The syntax rule reproduced earlier from the XSLT specification can be better understood by listing the seven different kinds of PathPattern , as follows:

Construct

Meaning

«/ »

Matches a document node.

RelativePathPattern

Matches a node that can appear anywhere in the document. Example: «book/chapter/title » matches any <title> element whose parent is a <chapter> element that is a child of a <book> element.

«/ » RelativePathPattern

Matches a node via a defined path from a document node. Example: «/book/title » matches a <title> element that is a child of a <book> element whose parent is a document node.

«// » RelativePathPattern

Matches a node that can appear anywhere in the document. The inclusion of the leading « / / » rules out nodes in trees that don't have a document node at their root. It also affects the default priority of a template rule that uses this pattern. The default priority of a pattern comes into play when two template rules match the same node: for details, see the description of <xsl:template> in Chapter 5 page 450. Example: «//title » matches any <title> element within a tree that is rooted at a document node.

IdKeyPattern

Matches a node with a given ID attribute or key value. For example, «id('A001') » matches an element with an ID attribute whose value is «A001 » .

IdKeyPattern «/ » RelativePathPattern

Matches a pattern defined relative to the children of a node with a given ID attribute or key value. For example, «id('A001')/title » matches the <title> child of an element with an ID attribute whose value is «A001 » .

IdKeyPattern «// » RelativePathPattern

Matches a pattern defined relative to the descendants of a node with a given ID attribute or key value. For example, «id('A001')//title » matches any <title> element that is a descendant of an element with an ID attribute whose value is «A001 » .

Usage

The pattern «/ » matches any document node. This means that if you have several trees (which will be the case in a stylesheet that uses the document() function described on page 532 in Chapter 7, or the doc() function described in XPath 2.0 Programmer's Reference), the pattern «/ » will match the document nodes of each one. This makes it difficult to write different template rules to match the document nodes of different trees. There are a few ways around this problem:

  • If your documents are of different types (that is, if they use different schemas, or different top-level elements in the same schema) then you can distinguish them using a pattern such as «document-node(schema-element(invoice)) » or «document-node(schema-element(purchase-order)) » . These constructs are described page 513 later in the chapter.

  • You can use different modes to process each tree (see the description of <xsl:apply-templates> page 187 in Chapter 5).

  • You can start the processing of secondary documents at the element node immediately below the root. A pattern such as «/item » will match an item element that is an immediate child of the document node. This kind of pattern is often useful when your stylesheet is dealing with multiple source documents, because it allows you to distinguish them by the name of the document element.

The pattern «/@width » is legal but meaningless; it would match a width attribute of the document node, but as the document node cannot have attributes, there is no such node.

To match every <para> element, use the pattern «para » in preference to «//para » . The latter will work (except in non-document trees) but its default priority is different, and it may be less efficient. For the other kinds of PathPattern , see RelativePathPattern (on this page) and IdKeyPattern (page 518) discussed later.

Examples

Construct

Meaning

/

Matches a document node.

/*

Matches the outermost element node in a document (the document element). In the case of a tree that is not well formed (see page 50 in Chapter 2), it matches any element whose parent is a document node.

/booklist

Matches any <booklist> element whose parent is a document node.

//book

Matches any <book> element that has a document node as an ancestor .

book

Matches any <book> element.

element(*, mfg:invoice)

Matches any element annotated as conforming to the schema-defined type mfg:invoice .

attribute(*, xs:date)

Matches any attribute annotated as an xs:date , including subtypes of xs:date .

id('figure-1')

Matches an element with an ID attribute having the value 'figure-1' .

id('f igure-1')//*

Matches any descendant element of an element with an ID attribute having the value 'f igure-1' .

key('empnr', '624381')/@dob

Matches the dob attribute of an element having a value '624381' for the key named empnr .

RelativePathPattern

A RelativePathPattern consists of a PatternStep defining conditions that a node must satisfy, optionally preceded by a RelativePathPattern that a parent or ancestor node must satisfy (the syntax puts it the other way around, but the effect is the same, and it's easier to think of it from right to left). The syntax for a RelativePathPattern is a subset of the syntax for a RelativePathExpr in the XPath Expression language.

Syntax

Expression

Syntax

RelativePathPattern

 PatternStep PatternStep / RelativePathPattern PatternStep // RelativePathPattern 

A RelativePathPattern is thus a sequence of one or more PatternSteps separated by either of the operators «/ » (is-parent-of) or «// » (is-ancestor-of).

The syntax of a PatternStep is described page 567 later in the chapter.

Effect

Because in practice patterns are likely to be evaluated from right to left, it's easier to explain the semantics if we rearrange the syntax, as follows.

Expression

Syntax

RelativePathPattern

 PatternStep RelativePathPattern / PatternStep RelativePathPattern // PatternStep 

With the first form, PatternStep , a node matches the pattern if it satisfies the conditions (node name, node kind, and predicates) defined in the PatternStep . The simplest and most common form of PatternStep is simply an element name, for example «title » .

With the second form, RelativePathPattern «/ » PatternStep , a node matches the pattern if it satisfies the conditions (node name, node kind, and predicates) defined in the PatternStep , and if its parent node matches the RelativePathPattern . This RelativePathPattern may in turn include conditions that the parent node's parent or ancestor nodes must satisfy.

With the third form, RelativePathPattern «// » PatternStep , a node matches the pattern if it satisfies the conditions (node name, node kind, and predicates) defined in the PatternStep , and if it has an ancestor that matches the RelativePathPattern . This RelativePathPattern may in turn include conditions that the ancestor node's parent or ancestor nodes must satisfy.

Usage

Notice that although there is an equivalence between RelativePathPattern in the pattern language and RelativePathExpr in the expression language, the meaning of a RelativePathPattern is most easily explained by examining the PatternSteps from right to left, starting at the node being tested and working up through its ancestors , if necessary; this is despite the fact that the meaning of a RelativePathExpr is explained by considering the Steps from left to right, starting at the context node. It's likely that most implementations will adopt a strategy similar to the algorithm as I've explained it here.

Generally speaking, there is no point in making patterns any more selective than is necessary. For example, if a <row> element always appears as a child of <table> , then there is no point in specifying the pattern as «table/row » -you might just as well use the simpler pattern «row » .

In theory, everything you can do in a RelativePathPattern could be done in a single PatternStep , since the pattern «A/B » means exactly the same as «B[parent::A] » , and the pattern «A//B » means exactly the same as «B[ancestor::A] » . However, where several steps are present, the form using «/ » and «// » operators is a lot easier to read.

Examples

Construct

Meaning

title

This is a PatternStep , and therefore the simplest form of RelativePathPattern . It selects any <title> element.

section/title

This is a RelativePathPattern consisting of two PatternSteps joined by the «/ » (is-parent-of) operator. It matches a <title> element whose parent is a <section> element.

chapter// footnote

This is a RelativePathPattern consisting of two PatternSteps joined by the «// » (is-ancestor-of) operator. It matches a <footnote> element that is a descendant of a <chapter> element.

chapter/section//footnote

A more complex RelativePathPattern that matches any <footnote> element that is a descendant of a <section> element that is a child of a <chapter> element.

chapter[1]//footnote

This pattern matches every <footnote> element in the first chapter (more strictly , in a <chapter> that is the first child <chapter> of its parent).

PatternStep

A PatternStep defines conditions that an individual node must satisfy: typically some combination of the node name, node kind, schema type, and a set of boolean or numeric predicates. The syntax for a PatternStep is a subset of the syntax for an AxisStep in the XPath expression language.

Syntax

Expression

Syntax

PatternStep

 PatternAxis? NodeTest-Predicates 

PatternAxis

 child :: attribute :: @ 

NodeTest

 NameTestKindTest 

NameTest

 QName * NCName :* *: NCName 

Predicates

 ([ Expr ]) * 

The syntax of KindTest is given page 510 later. The constructs QName , NCName , and Expr are all defined in the XPath 2.0 grammar, and are described in XPath 2.0 Programmer's Reference.

Effect

To describe the effect of a PatternStep we'll look at each of its components separately: first the PatternAxis , then the two kinds of NodeTest , that is, NameTests and KindTests , and finally the Predicates .

The PatternAxis

The PatternAxis may take the form «attribute:: » (abbreviated «@ » ) or «child:: » (abbreviated to nothing: « » ). In general, if no PatternAxis is specified, the child axis is assumed; the only exception is that when the NodeTest is an AttributeTest (for example, «attribute(*) » ), the attribute axis is assumed.

In the formal rules for evaluating a pattern, the steps in a RelativePathPattern are evaluated from left to right, and the choice of axis determines whether this step looks at the children or the attributes of the nodes found in the previous step.

Looking at it informally, it is simplest to think of the axis specifier as simply a way of saying what kind of node is required.

  • If the child axis is used and the NodeTest is a NameTest (for example, «title » , «* » , or «svg:* » ), then we are looking for an element node.

  • If the child axis is used and the NodeTest is a KindTest (for example, «comment() » or «text() » ), then we are looking for that kind of node. If the NodeTest is «node() » , then we are looking for any node on the child axis: specifically , elements, text nodes, comments, or processing instructions. Note that the pattern «node() » , which is short for «child::node() » will not match document nodes, attributes, or namespace nodes, because these nodes never appear as the child of another node.

  • If the attribute axis is used and the NodeTest is a NameTest (for example «@title » , «@* » , or «@svg:* » ), then we are looking for an attribute node.

  • If the attribute axis is used and the NodeTest is a KindTest (for example, «@schema-attribute(xml:space) » ), then we are looking for nodes on the attribute axis. Of course, the only nodes found on the attribute axis are attribute nodes. The patterns «@comment() » and «@text() » are not illegal, but they are pointless, because the attribute axis cannot contain comments or text nodes. However, the NodeTest «@node() » looks for any node on the attribute axis, so it is equivalent to «@* » .

If the PatternStep is the first PatternStep in a top-level RelativePathPattern , then it matches parentless nodes as if they had a parent. For example, the PatternStep «child::title » or «title » will match a <title> element that has no parent node, and the PatternStep «schema-attribute(xml:space) » will match an xml:space attribute that has no parent element.

The only two axes that are available directly in a pattern are the child and attribute axes. However, testing for the presence of related nodes on a different axis can be done in the predicate of the PatternStep . Any expression can be used in the predicate, and so all axes are available. For example:

  caption[preceding-sibling::*[1][self::figure]]  

matches a <caption> element whose immediately preceding sibling element is a <figure> element.

The NameTest

A NameTest such as «* » or «prefix:* » is purely testing the name of the node. This works whether or not there is a schema. There are four forms:

  • A lexical QName such as «title » . or «mfg:invoice » must match both the local name and the namespace URI of the node. If the QName has a prefix, then it is expanded using the namespace declarations on surrounding elements in the stylesheet; if not, the XPath default namespace is used. The XPath default namespace can be set using the [xsl:]xpath-default- namespace attribute, which is described in the entry for <xsl:stylesheet> in Chapter 5, page 442.

  • The NameTest «* » matches any node of the principal node kind for the axis.

  • The NameTest «prefix:* » matches any node whose name is in a particular namespace. There must be a declaration for this namespace (of the form «xmlns:prefix="uri" » ) on some enclosing element in the style-sheet module, and the namespace is the one with the corresponding URI.

  • The NameTest «*:local-name » matches any node with the specified local name, regardless of its namespace. This includes nodes whose name is not in any namespace.

In all these cases, a NameTest matches nodes only of the principal node kind for the selected axis. This means that if the PatternAxis is «@ » or «attribute:: » , the NameTest selects attribute nodes with the given name; otherwise, it matches element nodes only.

Patterns that match nodes by name are extremely common and work well with many kinds of document. If you find yourself writing a pattern with many alternatives, for example

  match="b  i  u  sub  sup  s"  

then (if you are using a schema-aware processor) it may be worth asking yourself what these elements have in common. One possibility is that they are all members of the same substitution group defined in the schema: in this case, you may be able to replace the pattern with one such as «match=" schema-element(inline)" » . Another possibility is that the elements all have the same internal structure. In this case they are likely to conform to the same type definition in the schema, so you can replace the list of elements by a pattern of the form «match="element(*, inline-type)" » .

If the list includes most of the members of a substitution group, or most elements conforming to a given type, then you could consider excluding the unwanted ones with a predicate, for example «match="schema-element(inline)[not(self::schema-element(span))]" » . Alternatively, if the pattern is being used to define a template rule, simply define another template rule with higher priority to catch the exceptions.

A pattern of the form «prefix:* » , which matches all the elements (or attributes) in a particular namespace, is often useful if all that you want to do is exclude such elements from the result tree. An empty template rule takes the form:

  <xsl:template match="svg:*" xmlns:svg="http://www.w3.org/2000/svg"/>  

This example causes all subtrees rooted at an element in the namespace http://www.w3.org/2000/svg to be excluded from the result. (This is the namespace for the W3C Scalable Vector Graphics specification: see http://www.w3.org/TR/SVG11/)

«*:local-name » patterns are new in XSLT 2.0. They should be used with care, because in principle the names in one namespace bear no relationship to names in a different namespace: for example, the «xsl:sequence » element in the XSLT namespace is quite unrelated to the «xs:sequence » element in the XML Schema namespace. However, there are cases where you might need to write a stylesheet that handles several namespaces that are variants of each other, in which many of the elements are common to more than one namespace. This construct can be very useful in this situation.

The KindTest

Whereas a NameTest is designed to match nodes primarily by their name, a KindTest matches specific kinds of nodes. In the case of element and attribute nodes, it also allows matching against the type annotation attached to the node as a consequence of schema validation.

The syntax of a KindTest , copied from the XPath specification, is as follows:

Expression

Syntax

KindTest

 DocumentTest  ElementTest  AttributeTest  TextTest  PITest  CommentTest  AnyKindTest 

DocumentTest

 document-node (ElementTest?) 

ElementTest

 BasicElementTest  SchemaElementTest 

BasicElementTest

 element ((ElementNameOrWildCard (,  TypeName ??)?)?) 

SchemaElementTest

 schema-element (QName) 

AttributeTest

 BasicAttributeTest  SchemaAttributeTest 

BasicAttributeTest

 attribute ((AttributeNameOrWildcard (, TypeName) ?)?) 

SchemaAttributeTest

 schema-attribute (QName) 

TextTest

 text () 

PITest

 processing-instruction ((NCNameStringLiteral)?) 

CommentTest

 comment () 

AnyKindTest

 node  () 

NodeName

 QName* 

TypeName

 QName* 

A KindTest is used to define the kind of node that is required and, optionally, information about its schema-defined type.

Let's take the simple cases first:

  • «text() » matches any text node.

  • «comment() » matches any comment node.

  • «node() » matches any node whatsoever (but remember that on its own, it means «child::node() » , which searches only for nodes that are children of something).

  • «processing-instruction() » matches any processing instruction node.

  • «processing-instruction(NCName) » matches any processing instruction node with the given name (the name of a processing instruction is referred to in the XML Specification as the PITarget ). For compatibility with XPath 1.0, the NCName may be written in quotes as a StringLiteral .

  • «document-node() » matches any document node.

  • «element() » matches any element node. This can also be written as «element(*) » .

  • «attribute() » matches any attribute node. This can also be written as «attribute(*) » .

Now things start to get more complicated, because the other kinds of KindTest are concerned with testing for specific types of node as defined in a schema. In general, you will use these KindTests only to match nodes in documents that have been validated against a schema.

KindTests for Element Nodes

Let's look first at the options for matching element nodes:

  • «element(QName) » matches any element node whose name is the given QName . As a pattern, this is exactly the same as writing the QName on its own. (The reason for providing this syntax is that a KindTest is allowed in contexts other than patterns, for example in the «as » attribute of an <xsl:param> element.)

  • «schema-element(QName) » is used to test for an element that matches a top-level element declaration in the schema identified by the given QName . It's an error to use this form unless you have imported a schema containing this top-level element declaration. For example, if you write «element(mfg:invoice) » , then the schema for the «mfg » namespace must have been imported, and must include a top-level element declaration of the form «xs:element name="invoice" » .

    The element is considered to match if two conditions are satisfied:

    • its name is either the same as the QName , or the name of an element defined in the schema to be a member of the substitution group with the named element as its head.

    • the type of the element node, identified from its type annotation, matches the type defined for this element declaration in the schema. This rule is there because a schema can allow the same name to be used in different contexts with different type definitions.

  • «element(*, QName) » is used to test for an element whose type annotation indicates that it has been successfully validated against the schema-defined type definition identified by the QName . The QName can identify a built-in type such as «xs:dateTime » , or a type (which may be a simple type or a complex type) that is the subject of a named type definition in an imported schema. The test will match any element that has a type annotation that refers to the named type, or a type derived from the named type by restriction or by extension.

  • If the element includes the attribute «xsi:nil='' true " » then it will match this KindTest only if the QName is followed by the symbol «? » . This extra test is necessary because without it, the system would not be able to make any assumptions about the contents of the element, since xsi:nil essentially allows an element to have no content even when the schema would otherwise require it.

  • The KindTest «element(QName, QName) » is essentially a combination of «element(QName) » and «element(*, QName) » . This tests both the name of the node and its type: the name must match the first QName , or the name of one of the elements in its substitution group, and the type annotation must match the second QName (which must be the name of a top-level type definition in an imported schema). Again, if the element includes the attribute «xsi:nil = " true" » then it will match this KindTest only if the second QName is followed by the symbol «? » .

KindTests for Attribute Nodes

KindTests for attribute nodes follow the same format as those for element nodes, with minor variations. The same options are available, though in practice they are likely to be used rather differently. For example, global attribute declarations are not used very often in XML Schema, and matching against the names of a top-level simple type definition is probably a more likely scenario.

  • «attribute(QName) » matches any attribute whose name matches the given QName: as a pattern, this means exactly the same as @QName or attribute::QName .

  • «schema-attribute(QName) » is used to test for an attribute that matches a top-level attribute declaration in the schema identified by the given QName . It's an error to use this form unless you have imported a schema containing this top-level attribute declaration. The attribute is considered to match if two conditions are satisfied:

    • its name is the same as the QName

    • the type of the attribute node, identified from its type annotation, matches the type defined for this attribute declaration in the schema

    • «attribute(*, QName) » is used to test for an attribute whose type annotation indicates that it has been successfully validated against the schema-defined simple type definition identified by the QName . The QName can identify a built-in type such as «xs:dateTime » , or a type (it will always be a simple type) that is the subject of a named type definition in an imported schema. The test will match any attribute that has a type annotation that refers to the named type, or a type derived from the named type by restriction. For example, the KindTest «attribute(*, xs:date) » matches any attribute whose type (as established by schema validation) is xs:date .

    • The KindTest «attribute(QName, QName) » is essentially a combination of «attribute(QName) » and «attribute(*, QName) » . This tests both the name of the node and its type: the name must match the first QName, and the type annotation must match the second QName (which must be the name of a top-level simple type definition in an imported schema).

KindTests for Document Nodes

The document-node()KindTest can take an argument that is an element() or schema-element()KindTest: it then matches any document node that has the specified kind of element as its only element child. For this KindTest to work, the document must be a well-formed document in the sense that the document node has exactly one element node as a child, and no text node children, and the element node must have been validated against a schema. Here are two examples.

Construct

Meaning

document-node(schema-element(mfg:invoice))

Matches the document node at the root of a well-formed document whose outermost element has been validated against the top-level element declaration named «invoice » in the schema for the namespace associated with the prefix «mfg » , or an element in the substitution group headed by the «invoice » element. This schema must have been imported into the stylesheet.

document-node(element(*, fin:movement))

Matches the document node at the root of a well-formed document whose outermost element has the type annotation «fin:movement » , or a type derived from this by restriction or extension. The schema for the namespace associated with the prefix «fin » must have been imported into the stylesheet.

Using KindTests

The simple KindTests comment(), processing-instruction(), and text() are used whenever you want to match one of these kinds of node. These are used comparatively rarely. For example, it's unusual to define a template rule that matches text nodes: usually a stylesheet will either copy text nodes unchanged, or suppress them from the output, and the choice is usually controlled from the template rule for the containing element node.

The default template rule for comment nodes causes them to be discarded; if you want to copy comment nodes to the output, you can achieve this by adding the template rule.

  <xsl:template match="comment()"><xsl:copy/></xsl:template>  

However, this will work only if the template rule used to process the containing element issues the instruction <apply-templates/> to process all its children.

The [schema-]element() and [schema-]attribute() KindTests are most useful when you a processing a source document that has been validated against a schema, especially when the schema is fairly complex. It allows you to define a generic rule for a whole class of elements or attributes. There are a number of ways such a class can be identified, and the approach you use will depend on the design of your schema:

  • Identifying the elements or attributes by type, using the syntax «element(*,QName) » or «attribute(*, QName) » is useful for processing elements and attributes that have simple content. For example, if all elements containing monetary amounts are identified as being of type «money » , then you can define a template rule with the pattern «match="element(*, money)" » that contains the formatting logic for values of this type. This will also work if the schema defines subtypes derived by restricting the money type, for example a subtype that restricts the values to be positive sums of money.

  • Where the schema defines many elements that share the same complex type, the syntax «element(*, QName) » can again be useful to define generic logic that applies to all elements of this type. For example, a schema for retail banking might define a generic type «movement » that represents all movements of money from one account to another. A template rule declared with «match="element(*, QName)" » will match all elements declared with this type, or with a type derived from it.

  • You need to be aware that in choosing a template rule, the system takes no account of the type hierarchy in the schema. If direct-debit is defined as a subtype of movement , this does not mean that the template rule defined with «match="element(*, direct-debit)" » takes priority over the rule with «match="element(*, movement)" » . You need to allocate explicit priorities in the stylesheet to make sure that the right rule is invoked.

  • If subtypes have been defined by extending the base type, then it can often be useful to invoke processing of the extensions by using the <xsl:next-match> instruction, described in Chapter 5. The template rule for the base type can process all the contents that are common to all instances of the type, while the template rule for an extended type needs to process only those contents that are included in the extension.

  • Sometimes substitution groups are used to define a collection of similar elements. Whereas types identify elements or attributes with common content, substitution groups identify elements that are interchangeable in terms of where they can appear in a document. The content of different elements in a substitution group might be completely different, in which case it is probably not very useful to define a template rule that processes all the elements in the group. More commonly, however, the elements in a substitution group will have some content in common, for example all elements in the substitution group of <event> might have attributes time and place . In this case a pattern such as «schema-element(event) » can be used to process this common content.

  • Patterns that match all elements in a substitution group can be especially useful in contexts other than <xsl:template> . For example, suppose a genealogy database allows a <person> element to contain any number of <event> elements among its children, and that elements such as <birth>, <death>, <baptism>, and < burial > are defined as elements within the substitution group for <event> . In this case, if you want to number the events for a particular person you can use <xsl:number count="schema-element(event)"/> .

Predicates

The form of a Predicate is defined in the XPath expression language: it is any expression enclosed in square brackets. For example «[speaker = 'Hamlet'] », or «[@width &gt;100] », or «[*] », or «[1] » . A PatternStep may include any number of predicates. These are additive-a node must satisfy all the predicates if it is to match.

There are two kinds of predicate: those that depend on the node's position relative to its siblings, and those that don't. A positional predicate is one whose value is a number, or one that uses the functions position() or last(); all others are nonpositional. For example, the predicates «[1] » , «[position()!=1] » , and «[last()-1] » are all positional predicates, whereas «[@name='Tokyo'] » and «[*] » are nonpositional.

For a nonpositional predicate, its meaning is that the PatternStep matches a node only if the effective boolean value of the predicate is true. The concept of effective boolean value is defined in XPath, and is summarized in the entry for <xsl:if> on page 309 in Chapter 5. For example, the predicate «[@security = 'secret'] » is true when the node has a security attribute whose value is 'secret' , so any PatternStep that uses this predicate will fail if the node has no security attribute or if the security attribute has any value other than 'secret' .

For a positional predicate, the meaning of the predicate can be deduced from the formal rules given at the start of this chapter. However, it is easier to understand their meaning by using informal rules. A numeric predicate such as «[1] » or «[last()-1] » is equivalent to the boolean predicate «[position()=!] » or «[position()=last()-1] » . So to evaluate a positional predicate, we need to know what position() and last() are.

The use of positional predicates with the attribute axis doesn't make much sense, because the order of attributes is undefined (though I did see one stylesheet that was using «@*[1] » to match the first attribute, and «@* » to match the others, which is perfectly legitimate so long as you realize that it's unpredictable which of the attributes will be the first). In the following description, I'll assume that you're using the child axis.

If there is only one predicate in the PatternStep , or if this predicate is the first, then:

  • last() is the number of siblings of the node being tested that satisfy the NodeTest (including the node itself). For example, if we are testing a <para> element against the pattern «para[last()=1] » , then last() is the number of <para> elements that are children of the parent of the <para> element being tested. This pattern will match any <para> element that is the only <para> child of its parent.

  • position() is the position of the node being tested among these siblings, taking them in document order and counting from one. So «para[1] » , which means «para[position()=1] » , will match any <para> element that is the first <para> child of its parent element, in document order.

Note that it is the position of the node relative to its siblings that counts, not the position in the sequence you are processing the nodes. For example, suppose you want to process all the <glossary-entry> elements in a document, in alphabetical order. You can write:

  <xsl:apply-templates select="//glossary-entry">   <xsl:sort/>   <xsl:apply-templates>  

Then suppose you have the following two template rules.

  <xsl:template match="glossary-entry[1]">   . . .   </xsl:template>   <xsl:template match="glossary-entry">   . . .   </xsl:template>  

The first template rule will be used for any <glossary-entry> that is the first <glossary-entry> child of its parent. Not, as you might expect, the first <glossary-entry> in alphabetical order, nor even the first <glossary-entry> element in the document. If you want to apply different processing to the <glossary-entry> that is first in alphabetical order, the way to do it is as follows.

  <xsl:template match="glossary-entry">   <xsl:choose>   <xsl:when test="position()=1">   . . .   </xsl:when>   <xsl:otherwise>   . . .   </xsl:otherwise>   </xsl:choose>   </xsl:template>  

This is because the context position within the body of the template rule is the position of the node in the list of nodes being processed , whereas the result for deciding whether a node matches a pattern is the same regardless of the processing context.

If there are several predicates in the PatternStep , then position() and last() in predicates after the first apply to the nodes that survived the previous predicates. So «speech[speaker='Hamlet'][1] » matches a <speech> element that is the first <speech> element among its siblings, counting only those <speech> elements in which one of the <speaker> s is Hamlet.

The position() and last() functions relate to children of the same parent even when the «// » operator is used. For example, «chapter//footnote[1] » matches any <footnote> element that is a descendant of a <chapter> element and that is the first <footnote> child of its parent. There is no simple way to write a pattern that matches the first <footnote> element in a <chapter> , because the relevant expression «(chapter//footnote)[1] » is not a valid pattern. (Why not? No good reason, it's just that the spec doesn't allow it.)

If you do need to write a template rule for the first <footnote> element in a <chapter> , the cleanest solution is probably to write your own function. You can invoke this in a predicate within the pattern, for example «match="footnote[test:position-in-chapter(.)=1] » . The definition of the function might look like this.

  <xsl:function name="test:position-in-chapter" as="xs:integer">   <xsl:param name="in" as="element()"/>   <xsl:number level="any" from="chapter"/>   </xsl:function>  

Positional predicates in patterns need to be used with some attention to performance. Writing a template with the match pattern «para[last()-1] » , for example, seems a sensible way to define the processing for the penultimate paragraph of a section. However, a simplistic XSLT processor will expand this predicate to «para[position()=last()-1] » , and evaluate it by first determining the position of the current paragraph in its section, then finding the total number of paragraphs in the section, and comparing the two. If the number of paragraphs in a section is large, this could be a very expensive operation. An optimized XSLT processor will find a better strategy, but if performance is critical it would be worth doing some measurements.

Examples

The following table provides some examples of PatternSteps .

Construct

Meaning

child::title

Matches elements named <title> .

title

Short form of «child::title » .

attribute::title

Matches attributes named <title> .

@title

Short form of «attribute::title » .

*[@width]

Matches an element node that has an attribute named width .

text()[ starts-with (.,'The')]

Matches a text node whose text content starts with the characters «The » .

p[@code][position()&lt;10]

Matches a <p> element that is among the first nine <p> elements of its parent that have a code attribute.

p[position()&lt;10][@code]

Matches a <p> element that is among the first nine <p> elements of its parent and that has a code attribute.

*[not(@code =

preceding-sibling::*/@code))

Matches an element node provided that it does not have a code attribute with the same value as the code attribute of any preceding sibling element.

comment()

Matches any comment node.

@comment()

This matches comment nodes that are found on the attribute axis of their parent node. Since the attribute axis contains attribute nodes only, this condition can never be satisfied; nevertheless, it is a legal PatternStep .

IdKeyPattern

This construct allows a pattern to be matched only if the node being tested (or one of its ancestors) has a specified ID attribute or key value.

This construct is a subset of the FunctionCall construct in an Expression, described in XPath 2.0 Programmer's Reference. The only function calls that can be used in a pattern (except within predicates) are the id() and key() functions, and these can be used only with arguments that are literals or variable references.

The id() function is an XPath function and is described in Chapter 10 of XPath 2.0 Programmer's Reference. The key() function is exclusive to XSLT, and is described on page 572 in Chapter 7.

Syntax

Expression

Syntax

IdKeyPattern

 id (Value) key (StringLiteral , Value) 

Value

 LiteralVariableReference 

For both the id() and key() functions, the required value of the ID or key can be specified as either a literal or a variable reference (in the form «$ » QName ). For the id() function, the only kind of literal that makes sense is a string literal (for example «"E-102" » ). For the key function, numeric literals also make sense if the key values are numeric. It is not possible to supply literals for other data types, for example xs:date values.

With the key() function, the first argument is the name of the key. This must be specified as a string literal, and it must match the name of a key defined in the stylesheet.

Usage

This facility provides an equivalent to the ability in Cascading Style Sheets (CSS) to define a style for a specific node in the source document. It can be used:

  • If for a particular source document you want to use a general-purpose stylesheet, but want to override its behavior for certain selected nodes, you can write a stylesheet that imports the general-purpose one, and then write the overriding rules in the form of templates that match specific identified elements in the source document.

  • Sometimes the source document is generated dynamically from a database. Perhaps there is something in the source document you want to highlight, say the search term that was used to locate this record. You could flag this item while generating the source document by giving it a special ID attribute value known to the stylesheet.

In practice, this construct isn't as useful as it might seem. Even though XSLT 2.0 has made it a lot more flexible by allowing the value to be specified as a variable (which in general is likely to be a stylesheet parameter), this form of pattern still achieves nothing that can't be achieved just as easily with a predicate, and is unlikely to be any more efficient.

For example, if <book> elements are keyed on their ISBN property, which is implemented as a child element, then the following declarations are equivalent:

Using a direct pattern match:

  <xsl:template match="book[isbn= '1-861002-68-8']">  

Using a key definition:

  <xsl:key name="isbn-key" match="book" use="isbn"/>   <xsl:template match="key('isbn-key', '1-861002-68-8')>  

Of course there may be a performance difference between the two, but this depends on how the XSLT processor is implemented. There is certainly no intrinsic reason why the predicate should be less efficient.

Examples

id('figure1')

Matches a node with an ID attribute equal to the string 'figure1' . An attribute is an ID attribute if it is defined in the Document Type Definition (DTD) or schema as having type ID (the name of the attribute is irrelevant).

key('empnr', $pers)

Matches a node having a value of $pers for the key named «empnr », where $pers is typically a stylesheet parameter .

The following example shows how this feature can be used in a stylesheet.

Using the key() Pattern to Format a Specific Node
start example

This example shows how to use the key() pattern to format one selected node differently from the others. The selected node will be specified by a style-sheet parameter.

Source

The source document, itinerary .xml , is a tour itinerary.

  <itinerary>   <day number="1">Arrive in Cairo</day>   <day number="2">Visit the Pyramids at Gaza</day>   <day number="3">Archaelogical Museum at Cairo</day>   <day number="4">Flight to Luxor; coach to Aswan</day>   <day number="5">Visit Temple at Philae and Aswan High Dam</day>   <day number=."6">Cruise to Edfu</day>   <day number="7">Cruise to Luxor; visit Temple at Karnak</day>   <day number="8">Valley of the Kings</day>   <day number="9">Return flight from Luxor</day>   </itinerary>  

Stylesheet

Let's start with a straightforward stylesheet, itinerary.xsl , to display this itinerary.

  <?xml version="1.0" encoding="iso-8859-1"?>   <xsl:stylesheet version="1.0"   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">   <xsl:template match="/">   <html>   <head>   <title>Itinerary</title>   </head>   <body><center>   <xsl:apply-templates select="//day"/>   </center></body>   </html>   </xsl:template>   <xsl:template match="day">   <h3>Day <xsl:value-of select="@number"/></h3>   <p><xsl:apply-templates/></p>   </xsl:template>   </xsl:stylesheet>  

Now let's specialize this by importing it into another stylesheet, today.xsl , which displays the activities for a selected day in red.

  <?xml version="1.0" encoding="iso-8859-1"?> <xsl:stylesheet   version="2.0"   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"   xmlns:xs="http://www.w3.org/2001/XMLSchema">   <xsl:import href="itinerary.xsl"/>   <xsl:param name="highlight-day" as="xs:integer" .required="yes"/>   <xsl:key name="day-number" match="day" use="xs:integer (@number) "/>   <xsl:template match="key('day-number', $highlight-day)//text() ">   <font color="red"><xsl:value-of select-"."/></font>   </xsl:template>   </xsl: stylesheet>  

To run this stylesheet using Saxon, enter the command line:

  java net.sf.saxon.Transform -t itinerary.xml today.xsl highlight-day=5  

Note that this example requires Saxon 7.9 or later (earlier versions do not support numeric keys).

Output

The resulting output is as follows, when the $highlight-day parameter is set to 5.

  <html>   <head>   <META http-equiv="Content-Type" content="text/html;   charset=utf-8">   <title>Itinerary</title>   </head>   <body>   <center>   <h3>Day 1<h3>   <p>Arrive in Cairo</p>   <h3>Day 2</h3>   <p>Visit the Pyramids at Gaza</p>   <h3>Day 3</h3>   <p>Archaelogical Museum at Cairo</p>   <h3>Day 4</h3>   <p>Flight to Luxor; coach to Aswan</p>   <h3>Day 5</h3>   <p><font color="red">   Visit Temple at Philae and Aswan High Dam</font></p>   <h3>Day 6</h3>   <p>Cruise to Edfu</p>   <h3>Day 7</h3>   <p>Cruise to Luxor; visit Temple at Karnak</p>   <h3>Day 8</h3>   <p>Valley of the Kings</p>   <h3>Day 9</h3>   <p>Return flight from Luxor</p>   </center>   </body>   </html>  

While this example shows one way of using this feature, I have to admit that it's not very convincing. You could achieve the same effect by writing the relevant pattern as «day[@number=5] » , without the need to introduce a key at all.

end example
 



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