Chapter 4. XPath Expressions

CONTENTS
  •  4.1 XPath Syntax and Terminology
  •  4.2 Abbreviations
  • Expressions

  • Location Path

  • Patterns

  • Axes, node test, and predicate

  • Position()

  • Abbreviations

XPath enables you to access parts of an XML document instance using "family affair" navigation relationships like ancestor, descendant, parent, child, and sibling. It provides the processor-readable (and human-readable) syntax for doing this, in the form of expressions.

In Chapter 1, we identified the tree structure by which XML addresses nodes in a document. In this chapter, we will explain the use of expressions, in the form of patterns and location paths, as well as location steps within those paths. We begin with the basic concepts of XPath, the XPath syntax and concepts like document order, context, and proximity. Chapter 5 will build upon these concepts with XPath functions, rounding out the intricate mechanisms that can be part of an XPath expression.

It is no accident that both the XPath and XSLT specifications became recommendations from the W3C on the same day in November 1999. XSLT elements rely entirely on the expressions provided by XPath to select and extract nodes from the input XML document. While many common functions of XSLT could be achieved with macros and scripts, XPath adds an easy, user-friendly interface.

Note

From observation of developers' lists and user groups for extensible markup technology, it quickly becomes clear that proper knowledge of XPath is frequently more challenging than mastering the variety of XSLT functions. Typically, an XSLT template will be properly written but will fail to operate correctly or as intended due to improper selection of a node-set in the match expression.

XPath expressions enable you to access any node or combination of nodes of an XML document with unlimited granularity.

There is a difference between knowing the path and walking the path.

Morpheus, The Matrix

XPath operates with the implicit assumption that, while you may know part of the logical structure or path for the nodes in a document, you don't need to know all of it. In other words, what you know of the document's detail and how much the XSLT processor can actually do with it can fortunately be two very different things.

4.1 XPath Syntax and Terminology

XPath provides a common syntax and semantics for addressing nodes in an XML document, and is used by both the XSLT specification and XPointer.[1] XPath was given its name to reflect its primary style of notation syntax, the path. This path reflects the same functionality as that of the URL, for instance. While the URL indicates a path to where a particular file is located, XPath indicates the particular path, based on the logical structure of an XML document, of where a given node is located. Paths are what the XSLT processor traverses in the course of matching, selecting, transforming, manipulating, and counting nodes. The paths are a form of expressions, which are the fundamental construct in which XPath manifests itself.

Note

XPath can be used throughout the many XML related specifications. For instance, it is used in the XSL Formatting Objects specification. It also applies to XPointer, XLink, and others. This book addresses XPath with respect to XSLT, but it should not be construed that XSLT is by any means its only venue of application!

In XSLT, XPath expressions are used as the values of attributes. Within those attributes' values, the XPath expression acts as a test for whether or not a given node matches the location path called for by the XSLT template. Before going into the details of the components of XPath, a simple example of how this syntax works will help to orient you to what follows.

Suppose you had a hard drive with a primary directory called "node", which in turn contained a folder or directory called "childnode" that had a file in it called "descendant". You would refer to the file using its location in UNIX by typing an absolute path such as:

/node/childnode/descendant 

In a DOS environment, this would be the same, only the slashes would face the other direction, and you would add the drive name:

c:\node\childnode\descendant 

If this looks familiar to you, then XPath syntax will be like working with an old friend. The XPath expression for this type of navigation looks like this:

/node/childnode/descendant 

Usually, you will see an XPath expression as the value of an attribute like match, select, or test in an XSLT element, as shown in Figure 4-1.

Figure 4-1. Using an XPath expression in XSLT.

graphics/04fig01.gif

In this figure, you can see how the syntax looks like a directory hierarchy. It is very important to note, however, that descendant, node, and childnode signify elements of a hypothetical XML document instance, not a file and the various directories containing it.

4.1.1 Document Order in XPath

Document order is a concept crucial to understanding and predicting how an XPath expression will behave with any given set of nodes. For Western languages, our understanding of "document order" is predicated upon the traditional narrative order in which we normally read: top to bottom and left to right. In XSLT, document order is predicated upon the hierarchical order of the elements and attributes, according to the tree structure of the XML document. Document order was covered in detail in Chapter 1.

4.1.2 The Context Node

The context node is the node that is selected prior to the evaluation of an expression. The context node is "handed" to the expression for evaluation, and the evaluation is performed using the context node as a starting point. The context node remains the same during the evaluation of the expression unless the expression is one of several special expression types that can change the context.

4.1.3 The Current Node

During the evaluation of an expression, each node that is being evaluated is the current node. The result of each evaluation is another node-set, with the current node as the new context. Sub-expressions use the new context node as their context node.

4.1.4 Context Size

The number of nodes that are being evaluated at any given point in the XPath expression is called its context size. Initially, this context size is equal to the number of nodes in the current node list, or the number of nodes that are children of the context node. Some expressions can change the number of nodes in the current node list, so the context size during the evaluation of an expression may be different from the original context size.

4.1.5 Proximity Position

The proximity position is the location of a node relative to its position in a node-set, or the numerical value of counting where a given node is (in document order) with respect to its sibling nodes in a node-set. Counting of nodes always begins with position 1 and proceeds forward, unless a reverse document order is specified.

4.1.6 Expressions

The XPath expression is a statement that the XSLT processor evaluates in order to yield a particular object as a result. The objects that are a result of an XPath expression can be one of four types:

  • node-set

  • Boolean (true/false)

  • number

  • string

Expressions are made up of tokens, as described in Section 4.1.6.1, and can contain functions (see Chapter 5) and variable references (see Chapter 8). An expression also can contain nested expressions, and so can be called either the expression or the set of expressions. Both terms are used interchangeably.

There are specific kinds of expressions called location paths that are used to extract nodes from an XML document. A subset of location path is called a pattern, which is further limited to selecting only element and attribute nodes. Location paths and patterns are discussed in Section 4.1.7.

4.1.6.1 Tokens

Each piece, or component, of an expression whether it is an element or attribute name, a symbol, an abbreviation, a forward slash, and so on is called a token. Some tokens can have several meanings, depending on their location in the expression. For example, the forward slash (/) can mean the root if it comes first in the expression, or it can indicate a step in the element hierarchy if it comes elsewhere.

The tokens are evaluated individually by the processor and then combined and/or contrasted with one another to produce a result.

Table 4-1 describes the different types of tokens and their values, some of which will be covered in further detail later in this chapter

Table 4-1. Tokens that are valid components of XPath expressions
Token Description
( Open Parenthesis
) Close Parenthesis
{ Open Brace
} Close Brace
[ Open Square Bracket
] Close Square Bracket
. Current Element
.. Parent Element
@ Attribute
* Element
, Comma
:: Separator
NameTest ElementName (NCName or QName)
NodeType Node Type (comment, text, processing instruction, or node)
Operator OperatorName (and | or | mod | div) or MultiplyOperator (*) or (/, //, |, +, -, =, !=, <, < =, >, >=)
Function-Name QName (used to identify a function) See Chapter 5.
AxisName ancestor, ancestor-or-self, attribute, child, descendant, descendant-or-self, following, following-sibling, namespace, parent, preceding, preceding-sibling, self
Literal

(" [^"]* ") | (' [^']* ')

strings that are delimited by single or double quotation marks (^" means anything except ")

Number [0 9]+('.' [0 9]+)? | '.' [0 9]+ (a floating-point number)
Variable- Reference $QName (used to recall the value of a variable) See Chapter 8.
4.1.6.2 Navigating XML with XPath Expressions

The simplest possible way to think of XPath expressions is to imagine someone giving you directions for finding something in a city; for instance: Keep going north along the main road until you see the boulevard, go right, then to the third block. A rendering of Markup City, introduced in Chapter 3, is shown in Figure 4-2.

Figure 4-2. A map of Markup City.

graphics/04fig02.gif

The XML version of this city was introduced in Chapter 3, and is presented again in Example 4-1.

With XPath, your expression can say: "Go to the third block in boulevard." Combining XSLT and XPath, we'd match the main road, the boulevard, and block information and test for the street we were seeking. Our XPath directions for navigating would use an expression that looks something like this:

/main/boulevard/block 

This expression would give you all the blocks in the boulevard. You would then need to distinguish between the six blocks by picking the correct one. The best way to do this is to count them and find the third block. To do this in an XPath expression, you need a little more than just the names of the elements.

/main/boulevard/block[position()=3] 

The word position here is an additional expression component that is called a function. Functions are the XPath version of macros. They call a process, usually passing in a parameter, and return a value. The position() function will be presented in more detail in Chapter 5, along with the other functions. However, it is worth introducing early on because it is extremely common and is almost indispensable for examples of how the various family heirarchy terms are used. The position() function does not take any parameters, and simply returns the numerical value of the position of the node within a context. In our example, we are testing to see if the value returned by the function is equal to 3.

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

In the XSLT stylesheet structure, using the <xsl:template> element, the same XPath statement appears as shown in Figure 4-3.

Figure 4-3. Using XPath expressions in XSLT.

graphics/04fig03.gif

In the example above, the XPath expression shows the selection of main, followed by boulevard, followed by the block found in the third position.

Note

The position() function works with careful reference to the concept of document order. The default sequence of nodes for XPath is the order and/or hierarchical location they have in the XML instance unless a specific operator is used to indicate reverse document order. In our example then, you could say that XPath always assumes that people are traveling one-way through town unless explicitly directed to do otherwise.

Beginning an XPath expression with /, as shown in Figure 4-3, signifies that this is an absolute path, starting from the root of the input document.

In addition to absolute paths, XPath expressions can be relative paths, with the expression starting at the current place in the document (see Section 4.1.7.3). Figure 4-4 shows the same expression again, but this time without the initial /.

Figure 4-4. Relative XPath expression.

graphics/04fig04.gif

The difference is that in Figure 4-3 we are starting from the root of the document, which means that the expression matches the root, followed by main, and so on. The relative path in Figure 4-4 would match main only if the context node contained a main element.

Consider the difference in meaning with the addition of /. Like UNIX, a starting / indicates an absolute location path in XPath syntax. The absence of a starting / means a relative location path. In our example, using the initial / signalled the processor to start looking from the root. Without the initial /, the processor starts looking from whatever node is currently selected when the expression is called, or the context node. The forward slash / has many uses and significations in XPath, which will be discussed in detail below, along with a further discussion of absolute and relative location paths.

We have all had the experience, when asking more than one person for directions, of getting many different sets of directions to the same place. As noted in the preceding section, XPath enables you to select nodes based on a range of complete or incomplete information. Suppose the number of blocks was not known, but your helpful local knew that some street with the name containing the word "Highland" was somewhere along the Boulevard. He might say, "Go down Main 'til ya hit the Boulevard, and then go on a few blocks 'til ya see the word Highland and turn right."

We could simulate this navigation with a pair of XPath expressions, as shown in Example 4-2.

Example 4-2 "Directions" to Highland Plaza, in XSLT and XPath.
<xsl:template match="/main/boulevard/block">       <xsl:if test="contains(. , 'Highland')">        <p>Turn right!</p>       </xsl:if> </xsl:template> 

As shown here, with XPath it is possible to match according to the contents of a particular string of data in a given node. We'll explain the specific syntax of contains() in Chapter 5. For now, our purpose is to display a sample of the full range of things that an XPath expression might be able to use for selecting quite literally any node.

XPath expressions operate on the basic assumption that you either know where you are going or you have a pretty good idea of what it is you want to find, or a combination of both, inside your XML document instance. For example, the same search can be accomplished using abbreviations as follows, without knowing where the block is:

//block[contains(., 'Highland')] 

Fundamentally, then, an XPath expression is a test of sorts. Notice that the names of the most frequently used attributes whose values contain XPath expressions have a meaning of evaluation: match, select, and test.

This is a key feature of XPath that must underlie all further considerations of how it works. XPath expressions are tests that are designed to yield a specific object as an outcome. The XPath expression is evaluated by the XSLT processor, and its outcome is an object, which is then "acted upon" by the attendant XSLT template functions.

4.1.6.3 Objects Yielded by Expressions

XPath expressions, regardless of their content, are designed to produce one of four object types: node-set, Boolean, number, or string.[2] While it may seem an abstract term, the "object" is simply the answer to what the XPath expression asks for, as if it were a question or query. Recall Example 4-2 from the previous section:

<xsl:template match="main/boulevard/block">       <xsl:if test="contains(. , 'Highland')">        <p>Turn left</p>       </xsl:if> </xsl:template> 

In the first line of the example, main/boulevard/block states: Find any block that is within the boulevard that is within main. The object returned is the list of <block> elements that fit those requirements.

The second line of the example narrows down the selection of blocks to the one that contains the word Highland. Using the function contains() in the test attribute we are asking for any block that has the string 'Highland.' Node-sets and strings are two kinds of objects yielded by expressions. In addition, there are Booleans (true or false) and numbers. An example of a number object would be the result of counting how many <block> elements are in the <boulevard>.

Node-set Objects

A node-set is an unordered group of unique nodes that is the direct result of the evaluation of an XPath expression. Node-sets can include nodes from any of the seven different node types: element, attribute, text, namespace, processing instruction, comment, or root. Regardless of the location of the original nodes in the tree of the XML instance, each node in the node-set is considered a sibling of the other nodes in the set. If the nodes in the node-set contain children, those children are not considered part of the node-set. However, further processing of the nodes in a node-set can provide access to those children.

It is important to note that node-sets are not the same as subtrees, or node branches. The resulting set of nodes from an expression does not include the children of those nodes.

In the previous example, our "directions" through the Markup City led us to the node-set consisting of a single node, the <block>Highland</block> element. In producing this kind of object, the XSLT processor is not required to maintain any specific document order, although most processors return the nodes in document order. Example 4-3 is our <year> example, repeated from Chapter 1.

Example 4-3 XML representation of a year.
<year>     <planting>           <season period="spring">                 <month>March</month>                 <month>April</month>                 <month>May</month>           </season>           <season period="summer">                 <month>June</month>                 <month>July</month>                 <month>August</month>           </season>     </planting>     <harvest>           <season period="fall">                 <month>September</month>                 <month>October</month>                 <month>November</month>           </season>           <season period="winter">                 <month>December</month>                 <month>January</month>                 <month>February</month>           </season>     </harvest> </year> 

If we used the expression match="/year/planting", then our resulting object would be a node-set containing a single node, the element node <planting>.If the expression was match="/year/planting/season", both <season> elements within the <planting> node would be selected. In other words, our object would be the node-set containing two <season> elements. The children of the nodes in the node-set, however, are not considered to be part of the node-set. They are part of the node branch. In Figure 4-5, a tree representation of an XML document instance is used to distinguish a node branch.

Figure 4-5. Diagram of an XML document instance showing a node-set and a node branch.

graphics/04fig05.gif

A useful way to think of the distinction between the node-set and the node branch is that a node branch always represents the original XML document's hierarchy of logical structure for that set of nodes. A node-set can contain nodes from any level and is not explicitly ordered.

Boolean Objects

An XPath expression that evaluates to either true or false returns a Boolean[3] object.

A Boolean expression is basically like a true-false question on a test. We can make a simple Boolean test for whether or not a <year> in our example happens to contain <month> descendant nodes (which it does). Using XPath specific syntax, the expression would be written as follows:

boolean(/year//month) 

Boolean: [first computer usage] Boolean operation, an operation depending on the application of the rules of Boolean algebra. By extension, any operation in which the operands and results take either one of two values or states, i.e., any logical operation on single binary digits. Gloss. Autom. Data Processing (B.S.I.) 29, 1962. (OED, 2000, II: 398)

If the function is to be used in the XSLT <xsl:value-of> element, the expression would be the value of the select attribute:

<xsl:value-of select="boolean(/year//month)" /> 

Note

Throughout the XPath chapters, we will provide examples in both XPath syntax and XSLT syntax. You can use the XSLT syntax examples to test your own examples.

This expression uses the boolean() function to evaluate the statement /year//month. The evaluation produces a node-set, and the boolean() function converts the node-set into a true or false test. Because the result of the evaluation produces something other than a null or empty result, the final object produced is the Boolean "true" because the element <year> does contain <month> descendants. If the result had been null or empty, the boolean() function would have returned a "false" Boolean object.

Boolean objects usually result from the evaluation of an XPath expression that contains one of several kinds of tokens, called operands.

Operands are simple kinds of logical connectors and can be classified as "or" or "and" expressions, as well as various equality or relational expressions. The operands are:

  • or

  • and

  • > (greater-than)

  • < (less-than)

  • = (equals)

  • != (not equal)

  • <= (less-than-or-equal-to)

  • >= (greater-than-or-equal-to)

Note

Using the < (less-than) character will cause the XML parser to generate an error because it is not allowed in an XML document unless it is part of a tag. It must be escaped with the XML entity &lt; when used in an expression.

The | (pipe) symbol, which is a common replacement for the or operator, can also be used in an expression, but results vary from the use of or because the processor treats the expression differently, depending on which operator is used. For example, <xsl:value-of select="//harvest | //planting" /> returns the value of the contents of the <planting> node, even though //harvest comes first in the expression, because the expression evaluates the nodes in document order, and <planting> comes before <harvest> in our example. Because the expression uses the | symbol, the evaluation of the expression acts as if each part of the expression (each operand) stands alone. When an expression is simply a pattern, the result is a node-set, and in this case, (because of the <xsl:value-of>) the entire contents of the <planting> node are returned. In other words, the | symbol separates the two parts into individual expressions and evaluates them as such.

On the other hand, when using the or operator, <xsl:value-of select="//harvest or //planting" /> results in the value true because, when using the or operator, the processor evaluates each operand and converts its value to a Boolean prior to the comparison. In other words, this expression is the same as:

<xsl:value-of select="boolean(//harvest)" /> 

or

<xsl:value-of select="boolean(//planting)" /> 

The result is true if either //harvest or //planting exist in the document. The second value (//planting) will not even be evaluated if the first value (//harvest) is found to be true.

Using our example of Markup City, the following expression "asks" whether <main> has a <parkway> and a <boulevard>:

boolean(/main/parkway and /main/boulevard) 

or

<xsl:value-of select="boolean(/main/parkway and /main/boulevard)" /> 

Notice in this example that we are using the operand and. In any given Boolean, the order of evaluation is from left to right. If the left-hand side of an and expression proves false, then the entire expression is false. The same is also the case if there are several and operands in a row: as soon as one comes up false, then the statement is false.

The or operand functions slightly differently. It is still evaluated from left to right, no matter how many or constructions there are. However, if you are testing for a value of true, then once any single part of the or expression yields true, then that entire Boolean expression is determined to be true, and no further portions of the or expression are evaluated (unless there are substrings, which are evaluated first).

Number Objects

XPath expressions can be constructed in such a way that when they are evaluated, their result yields a number as the object. In XPath, any object of type number is a digit or group of digits (a floating-point number).[4]

Number objects are often produced by evaluating an expression in a way that "counts" nodes. For example, we might want to know the number of months in the <harvest>. We can use the count() function (discussed in detail in Chapter 5) to count how many <month>s are descendants of <harvest> as follows:

count(//harvest//month) 

Of course, we already know that the number of <month> nodes in the <harvest> portion of <year> is six, but what is important to realize is that the object produced by evaluating the expression is a number. The XPath expression //harvest//month returns a node-set of the month elements that are descendants of <harvest>. The count() function converts that node-set to a number, in this case, 6.

Numbers are often used together with Booleans for a variety of tests upon node-sets to determine whether or not to perform a given manipulation of the node-set in question. XPath number evaluation can also be used to count how many words, paragraphs, or specific element nodes an XML data instance might contain in a given chapter, section, or regional category, for example.

String Objects

What is most obvious can also be the most obscure when it comes to explaining or defining something. A "string" is simply a sequence of characters[5] whether the content of a particular element node, attribute value, attribute name, element-type name, or token in an expression. For instance, from the XML shown in Example 4-3, the word year is a string just as the word August, as the content of the <month> node inside the <harvest> portion of the <year>, is a string. So also are harvest and month strings, and so on.

For example, the function name(), discussed in Chapter 5, returns the string value of the element-type name. As shown in previous Example 3-17, <xsl:value-of select="name()" /> returns either "block" or "sidestreet" depending on the context of the expression.

4.1.7 Location Paths

A location path is a type of expression that enables the selection of a set of nodes, based on a context. Unlike other expressions, a location path always returns a node-set. A subset of location paths in XSLT is called a pattern. Locations paths can be absolute or relative, and consist of a series of location steps separated by a /. Location paths are perhaps the most "XML-aware" expressions in XPath because they specify a location based on the XML document's tree hierarchy.

4.1.7.1 Patterns

The most basic form of an XPath expression is a pattern, defined in the XSLT specification[6] as a form of location path that addresses nodes in a particular context. Patterns are a subset of location paths that only allow the use of the child axis, discussed in Section 4.1.8.13, and the attribute axis, discussed in Section 4.1.8.8.

4.1.7.2 Absolute Location Paths

An absolute location path is a path that is evaluated with the root node as the starting point. It always begins with a /, and can optionally be followed by a relative path. If the / is by itself, it references the root node of the XML data instance. In effect, an absolute location path is a relative location path, but it is one that is always relative to the root node.

An absolute location path functions similarly to an absolute location path in UNIX. Regardless which directory you are in, you can navigate to any directory on the server or network by initiating the directory or file locator path with a /. The same holds for absolute location paths in XPath.

4.1.7.3 Relative Location Paths

A relative location path is a path that is evaluated relative to the context node. The context node acts like the current directory much like a relative location path in UNIX the present working directory (pwd). You can switch to a directory that is lower in the hierarchy by naming it without a preceding /. If you were to use a preceding / in UNIX, it would take you to the root of the system, just like an absolute path (see Section 4.1.7.2).

A relative location path has a sequence of one or more location steps separated by /. The forward slash functions like a directory delineator in UNIX. In the XPath expression, the / serves to distinguish between one level, or step, of the markup hierarchy and another. Each step is separated by a forward slash that serves to indicate the traversing of the step. As each step is traversed, the context node changes relative to that position in the location path, and the node-set selected by each step becomes, in turn, the context node for the following step.

4.1.7.4 Location Steps

Movement from one level in the XML hierarchy to another in a location path is called a location step. Each location step in a location path is separated by a forward slash (/).

A location step can be thought of as going up and down steps from one level to another, because you are stepping up and down the node tree, from parent to child, and so on. Using the XML in Example 4-3, a <month> is a step down from <season>, and a <season> is a step down from <planting>, giving us the following location path:

planting/season/month 

A location step is made up of an axis, a node test, and optionally one or more predicates. In this example, only the node test for each step is shown, because the axis is defaulted, and the predicate is optional. Figure 4-6 shows a location step with its parts identified.

Figure 4-6. Axis, node test, and predicate in a location step.

graphics/04fig06.gif

The axis is the relationship between the location step and the context node. The node test defines which type of node to select (element, attribute, etc.) and the expanded name of the nodes to test for. If the expanded name of a node matches the node test, and the node is of the correct type, the node is selected. A predicate is an expression within a location step that qualifies or refines the selection of the node-set within the specified axis. These concepts are discussed further in the following sections.

4.1.8 The Axis

The axis in a location path is the relationship, with regard to the tree structure, between the location step itself and the context node. It is important to underscore that the axis is not a "place," or a node. It is a relationship.

The relationships that can be represented by the axis are: ancestor, ancestor-or-self, attribute, child, descendant, descendant-or-self, following, following-sibling, namespace, parent, preceding, preceding-sibling, and self.

The default axis for an XPath location expression is the child axis. Every node except for the root is the child of another node, so every location step begins with the child axis as its axis. The root, however, is not a child of anything, so its default axis is the self axis.

Consider again the following example:

planting/season/month 

The axis for <season> (although it is not explicitly stated) is that of a child of <planting>. The axis for <month> is that of a child of <season>.

There are two ways to represent a location step, either using the abbreviated syntax as we have shown here, or using the full syntax as specified by XPath. In normal use, the abbreviated syntax is commonly used. We mentioned that the default axis for a location step is the child axis. Therefore, in all of the expression examples with location paths that we've shown you, the default axis is that of the child. However, we never explicitly wrote this out. If we had, for the example above, our location path expression would look like the following:

child::planting/child::season/child::month 

As we explained, the axis for <season> is that of a child of <planting>. Since any relative path has as its default axis the child axis, it is rarely, if ever, seen in practice. This point is better understood if you remember that explicitly stating child:: does not say anything more than what is said simply by using the element-type name alone.

We have also introduced another token in this example, the separator ::, which serves to indicate the separation between the axis and the node test. In the location path above, child is the axis, and :: indicates that what is to come next will be the node test in this case, a node test for all <month>s that are children of <season>, or all <season>s that are children of <planting>.

The separator :: can be read as "that are." The proper way to read this is sort of like RPN (Reverse-Polish Notation). Reverse-Polish Notation, a long-standing convention of right-to-left reading of mathematical and logical expressions, is the common syntax for reading most logical expressions in XPath. To read the :: in the location path for the expression above, we would say "all month children of season nodes that are children of planting."

4.1.8.1 Parent Axis

The parent axis contains the parent of the context node, provided such a node is available. For any given node that is a child, there is only one parent (remember, single-parent families make up the familial infrastructure of XML data instances).

From our <year> example, assume our context was a <month>. Using the location step parent::season would select the <season> node that contains the month. This literally says, "select those nodes that are called <season> that are parents of the context node." Of course, you would almost never have to specify a parent node by name, because any element has only one parent.

When considering document order, this axis is considered to be a reverse axis. A reverse axis specifies a reverse direction from normal document order.

4.1.8.2 Ancestor Axis

The ancestor axis contains all nodes that are one level or more above the context node. When used with a specific node name, it picks the first ancestor node with that name regardless where it appears in the hierarchy above the context node. For instance, if the context node is <month>, using ancestor::planting selects the <planting> node. In human terms, this example says "select any node that is called planting that is an ancestor of the context (which is <month>)."

The ancestor axis always includes the root node, unless the context node is the root node.

When considering document order, this axis is considered to be a reverse axis.

4.1.8.3 Descendant Axis

The descendant axis contains all nodes that are one step or more below the current context node. When used with a specific node name, it selects that node regardless where it is in the descending hierarchy from the context node, for instance, from <year>:

descendant::month 

This selects all the <month> elements. In other words, this says "select any <month> elements that are descendants of the context node (which is <year>)."

When considering document order, this axis is considered to be a forward axis. A forward axis specifies a normal direction for document order.

4.1.8.4 Following-sibling Axis

The following-sibling axis contains those nodes at the same hierarchical level as the context node that follow it in document order and share the same parent:

following-sibling::month 

This will select any months following the context <month>. For instance, consider an example drawn from the "winter" season.

<season period="winter">       <month>December</month>       <month>January</month>       <month>February</month> </season> 

If the context <month> is the <month> containing the string January, then the only node selected by following-sibling::month would be the <month> containing the string February.

It is important to consider that if the context node is an attribute node or a namespace node, the following-sibling:: axis is empty. This is because attribute and namespace nodes are not required to be in any particular order.

When considering document order, this axis is considered to be a forward axis.

4.1.8.5 Preceding-sibling Axis

The preceding-sibling axis contains those nodes that precede the context node, at the same level in the document hierarchy, sharing the same parent. Let's look at this example:

preceding-sibling::month 

If our context node were the <month> containing the string February, then we would be selecting both <month>s with the respective strings December and January. As above, if the context node were to be an attribute node or a namespace node, the preceding-sibling:: axis would be empty.

When considering document order, this axis is considered to be a reverse axis.

4.1.8.6 Following Axis

The following axis contains those nodes that come after the context node in document order. An important consideration to this, however, is that the descendants of the context node are not included in this axis, but all descendants of all following siblings, and all following siblings are included. In other words, this axis can jump from one node branch to another.

If we were to name a node like <harvest>, then this node would be selected from all the nodes following the context node. Therefore, from our <year> example, we could select as follows, with our context node being the <planting> node:

following::harvest 

This would select the <harvest> node following the <planting> node.

When considering document order, this axis is considered to be a forward axis.

4.1.8.7 Preceding Axis

The preceding axis contains all nodes that come before the context node. It does not select ancestors of the context node, but it does select ancestors of any other nodes that precede the context node but are not its ancestor. In other words, this axis can jump from one node branch to another.

If our context node was the <season> with the attribute of fall, we would select as follows:

preceding::season 

This would not select anything in the <harvest> node, of which the "fall" <season> is a descendant. It would, however, select the "summer" <season> from the <planting> node branch. This would also, then, include the "spring" <season>, as it also precedes summer in document order, and is not in the same ancestor branch as the context node.

As with the following axis, attribute and namespace nodes are excluded.

When considering document order, this axis is considered to be a reverse axis.

4.1.8.8 Attribute Axis

The attribute axis contains all the attribute nodes of the context node. The attribute axis is represented by attribute::; however, this is rarely seen and we have begun working with this axis in its abbreviated form, @. The following are all correct uses for the attribute axis:

attribute::period @period attribute::* @* 

These examples show the use of the wildcard * to select an attribute of any name. Selecting an attribute will return the value of the attribute, unless that attribute is not specified, in which case it will return a null value.

When considering document order, this axis cannot be ordered either forward or reverse. It is considered a non-ordered axis.

4.1.8.9 Namespace Axis

The namespace axis contains the namespace node of the context node and, unless this context node is an element, it will be empty. For the following example, we might have a namespace for the seasons, and a different one for instance, standard for a standard calendar month which have already been declared elsewhere, such as in the root element.

<iowa:season period="fall"> <standard:month>September</standard:month> <standard:month>October</standard:month> <standard:month>November</standard:month> </iowa:season> 

We would select the namespace node based on the context node. If our context node was <season>, namespace::iowa would select the iowa: namespace.

Namespaces, like attributes, are not treated with any particular document order. This is a non-ordered axis.

4.1.8.10 Self Axis

The self axis selects exactly that: the node that is the context node. For example:

self::season 

This would select the context node, if and only if the context node was a season. This is useful in instances where you are working through many different nodes and need to test to see if a particular node is of a certain type.

One way to think of the applicability of the self axis (and it is used frequently in more complex expressions with predicates) is with the root node, which is not contained in any child axis.

Since the resulting node-set only ever contains one node, document order is not relevant. It is, as a result, a non-ordered axis because there is nothing to order.

4.1.8.11 Descendant-or-self Axis

This axis contains the context node and all of its descendants. Specifying a name for the node test would take any node with the name that is a descendant of the context node or is the context node itself, if it has the same name.

Given descendant-or-self::season, if the context happened to be the root, the expression would result in a node-set of all the seasons in the document. If the context happened to be harvest, only the seasons in harvest would be returned. If the context was a season, it would return that season.

When considering document order, this axis is considered to be a forward axis.

4.1.8.12 Ancestor-or-self Axis

This is the same principle as the descendant-or-self axis, only in reverse document order. The ancestor-or-self axis selects from the context node and all of its ancestors. When considering document order, this axis is considered to be a reverse axis.

4.1.8.13 Child Axis

The child axis is designated if made explicit by child:: and this serves to indicate that the current node is a child of whatever the context node is. Only the root does not have a child axis.

Since every node is otherwise a child of its context, the child axis is the default axis and need never be explicitly stated.

When considering document order, this axis is considered to be a forward axis.

4.1.9 The Node Test

Every location step contains a node test. The node test contains the name of the nodes the processor should test for. If the name of a node matches the name of the node test, and the node is of the correct type, the node is selected. If the nodes being tested for have a namespace, the expanded name of the node must be used. The node type being tested for is determined by the axis.

The node test depends on the axis to determine the type of node it will select. For example, if the axis is "attribute," the node test will only look at attributes. If the axis is descendant, ancestor, child, etc., which can contain elements, then the test only looks at elements.

The node test, then, uses a combination of both the axis to determine the type of node to search for, and the name of the node to only select nodes with that name.

There are two node tests in the following location path, season and month.

<xsl:template match="child::season/child::month" /> 

The first node test searches for any node that is a child of the context node, and also has a name "season." The second node test does the same for the month node name. The type of node the node test is looking for is an element, because the axis in this case is child. Only elements are considered when the child axis is used.

Attribute names are treated slightly differently. When looking for attributes, the axis attribute::, must be used, signalling that the node test is for an attribute. For instance, we could look for an attribute called period that is a child of season as follows:

season/attribute::period 

Of course, <season> elements have only one kind of attribute, those called period, so this example is a little bit of overkill. One of the abbreviations for any element or attribute name is *. We could change the example to look for any attribute of season, as follows:

season/attribute::* 

We can also use the // descendant abbreviation to look for any attribute called period anywhere in the document:

//attribute::period 

What this path says is "start from the root and find any attribute named period." You might use this to get the elements in a document that have href for URI links, for instance.

//attribute::href 

4.1.10 The Predicate

Predicates add an additional level of testing to a location step. They filter the node-set selected by the node test, within the context of the location step. Predicates are indicated by the presence of square brackets, the [ and ] tokens, and use additional expressions to perform additional levels of node filtering.

A common use of a predicate is to select elements based on whether they contain other elements or attributes. In our previous examples, using season/attribute::period returned the attribute node, not the element node. If we wanted to get the elements that contained attributes, but not the attributes themselves, we would use a predicate as follows:

season[attribute::period] 

This returns the season element, but only if it has a period attribute. In this expression, the axis for season (not explicitly stated) is the child:: axis. The node test is season, and the predicate is [attribute::period]. The predicate tests for whether or not there is a period attribute on the season.

Multiple predicates can be used, and their resulting values are passed up to the initial node test after all their filtering is completed. For example:

season[following-sibling::*[@period='summer']] 

This expression asks for a <season> that has a following-sibling of any element name, *, provided it has an attribute with the name period and the value "summer". It will return the spring <season>.

Predicate expressions are evaluated for each node in the current node-set to determine if that node will be passed along to the next test or subexpression as part of a new node-set.

Some predicates can change the number of nodes in the current node list, so the context size during the evaluation of a predicate may be different from the original context size.

In //season[following-sibling::*[@period='summer']], the context size for the node test of season is 4 (the number of all the seasons). The predicate asks for any elements that are following siblings, reducing the context size to 3, and the sub-predicate narrows it down to only those following siblings that have an attribute period with value of "summer", reducing the context size to 1. The result of this expression is the one node (season) that matches all the requirements.

4.1.10.1 Using position() with Predicates

The numerical value of the position of a node is frequently used in predicates. The position() function simply provides a numeric reference to the position of a given node. This is the number of the current node in the current node list. This list is counted in document order but, unlike in some programming languages, it is not zero-based. The first position, in document order, is 1.

The position() function can be used with mathematical operators to select specific nodes based upon their position in document order. Accordingly, in our example of the <year>, for any given season, we could select the <month> that is in first position:

month[position() = 1] 

or

<xsl:template match="month[position() = 1]"> 

Depending on the context where this expression is used, the value returned is the first <month> in that context. If the context is the root, the first month in the document is returned:

<month>March</month> 

It is also possible to test positions based on an arbitrary number or position. Suppose it was necessary to mark the middle <month> of each <season> perhaps for an evaluation of how the respective planting or harvest progress was proceeding in accordance with the current weather based upon its position. You could use the following XSLT element and XPath expression, assuming the context node is that of <month>:

<xsl:if test="position() = 2" >       <!-- do something --> </xsl:if> 

In this case, the test attribute yields a Boolean true or false, which when true causes whatever we had specified in between the <xsl:if> tags to be applied to the selected nodes.

Remembering that a step in a relative location path is distinguished or identified by /, we can set up a sequence of successively complex location expressions:

season[@period='summer']/month[position() != last()] 

There are two steps in this expression, one with the node test of season and its predicate filter on the attribute name period with the value of summer, and the other is the node test on month, with the predicated filter specifying using !=, the "not equal" operator the position not equal to last. In this expression, we used a new function, last(), which returns the position of the last node in a node-set. last() will be discussed in more detail in Chapter 5. You should know there is a "last" function, but there is no first, second, and so on, because the numerical values of 1 and 2, and so on, are the correct format.

For this and the preceding example, the output would be:

<month>June</month> <month>July</month> 

Complexity of selection for the layers is unlimited. For example, the third <month> of the first <season> on the following:: axis would be written as:

following::season[position() = 1]/month[position() = 3] 

The result of evaluating this expression when the context node is <planting> is the <month> node containing the string October. Remember that the following:: axis does not select any children of the current context.

Other mathematical operators can also be used with the position() function to specify a range, for instance, using > (greater-than), or < (less-than). However, remember that, because we are using XML, the < symbol for less-than must be replaced with the &lt; entity:

following::season[position() = 1]/month[position() &lt; 3] 

4.2 Abbreviations

Throughout the preceding sections, we have touched upon various abbreviations used for XPath axes, names, and functions. The most common is the abbreviation, by way of omission, for the child:: axis. That abbreviation, of course, is simply an absence. The presence of a node name, such as an element-type name, indicates the child axis by default.

Another fairly "minimalist" abbreviation is that for the self:: axis. This derives directly from UNIX directory syntax and is simply "." a period by itself.

Not surprisingly, then, the common referent for the parent directory in UNIX is also seen as the abbreviation for the parent:: axis in XPath location expressions: ".." two periods.

The descendant:: axis can be abbreviated with //. The double-forward slashes represent any possible number of intervening nodes between the context node and the node being selected by the expression. Thus, the <month> descendants of the year can be equally referenced, as follows:

year/descendant::month 

or

year//month 

Another useful abbreviation, is the asterisk, *. When used alone, the * is short for "all element children of the context node." We could use the following expression to select all elements in the document.

/* 

The attribute:: axis can be abbreviated using @:

@period 

Abbreviated attributes can also be used with * to indicate all attributes in the context node:

@* 

Another very important abbreviation, which bears upon the frequency and importance of the numerical value of the position of any node in the XML data instance, is for the predicate [position() = X], where X is a numerical value or the function last(). This entire predicate can be abbreviated using only the square brackets, [ ], and the number or last(). For example: [2] is the same as [position() = 2]. Similarly, you could have [last()] to select the last node of the context node.

Combining some of these abbreviations, we can select the last <month> in the <season> by using:

season/month[last()] 

We can use the element name wildcard to get the last element in the season:

season/*[last()] 

We can select any element that has an attribute whose value is winter:

//*[@* = 'winter'] 

Notice that this expression matches any attribute regardless of the name of the attribute.

Abbreviations for axes, names, and functions are the common way XPath expressions are written. The abbreviations are summarized in Table 4-2.

Table 4-2. Abbreviations for axes and functions
Abbreviation Function
. the self:: axis, or the context node
.. the parent:: axis
* a "wild card" for element and attribute names
@ attribute, or the attribute:: axis
@* a combination of the attribute abbreviation and the "wild card" for name which selects all attributes of the context node
// the descendant:: axis
../ the following-sibling:: axis
[2] short-cut for [position() = 2]

[1] XPointer details an extendable syntax for addressing system-wide file and directory locations. See http://www.w3.org/TR/xptr.

[2] It is possible there could be other types. Quoting from the XPath specification, section 4.1: "An object of a type other than the four basic types is converted to a string in a way that is dependent on that type." This of course means the object could be something completely unknown!

[3] Boolean objects are named after the series of operators devised by George Boole (1815 1864).

[4] Number values in XPath are predicated upon the IEEE 754 specification for numerical values and equivalences. In essence, it is the basic notion of a floating-point number and can have any 64-bit format "double-precision value." For most readers, this basically means that a 6 is a 6 is a 6, unless it's three sixes in a row, which for other readers might have an entirely different signification. However, numerically, per IEEE 754, it is simply a set of number values for hexadecimal computing and mathematical manipulation following the predicated rules of algebraic logic. If terms like floating-point and double-precision are unfamiliar to you, all you really need to know about the nature of number objects in XPath is that they are and act like what you would normally expect of any rational number.

[5] The Oxford English Dictionary gives the meaning for a string as "a number of things in a line; a row, chain, range" (00, XVI:922). The XPath specification states, among other things, "a sequence of zero or more characters, where a character thus corresponds to a single Unicode abstract character with a single corresponding Unicode scalar value this is not the same thing as a 16-bit Unicode value ." Most of the details about Unicode and scalar values have to do with the specifications for writing XSLT processing software, specifically as regards the complex issue of character coding and multilingual XML data instances.

[6] Patterns are not explicitly defined in XPath, but are a subset of expression, as defined in the XSLT specification.

CONTENTS


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

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