Chapter 5. XPath

Table of Contents

Expressions
Steps
Combining node sequences
Abbreviations
XPath 2.0 functions by categories

The XML Path Language (XPath) is a declarative, expression oriented query language which is used for selecting nodes from an XML document. XPath 1.0 became a Recommendation in 1999 and is widely implemented and used, either on its own (called via an API from languages), or embedded in languages such as XSLT, XProc, XML Schema or by the discontinued XForms. The primary goal of XPath is to provide a toolset for accessing different parts of an XML document. In practice it means one can use it for addressing, identifying, referencing and locating the (element, attribute, text and all the defined) nodes from an XDM instance. It is based on the logical structure of the document and used for selecting nodes. We can filter all the elements and attributes by different expressions, we can navigate between them using the parent-child relation and we can modify all the values from any supported data types. Finally but not last, it supports namespaces.

Over the node selection functionality it contains built-in functions to deal with data types from text to logical ones, and supports node and node sequences manipulation. XPath did not define anything for the result, its the underlying XPath implementation’s task. XPath 2.0 is the current version of the language; it became a Recommendation in 2007. A number of implementations exist but are not as widely used as XPath 1.0. The XPath 2.0 language specification is much larger than XPath 1.0 and changes some of the fundamental concepts of the language such as the type system and the default set oriented behaviour is replaced by sequences. Every expression returns a sequence and several new functions were introduced to support this aspect. Its latest (and most current) version was published in 2010. However, a newer edition, version 3.0 is on its way and currently it is a proposed recommendation dated on 22 October 2013. It has some new aspects: functions became first-class values, so they can be used inline, or as an argument or as a return value which overcomes the limitations of the XDM type system. Nevertheless, in the following sections we will use the XPath 2.0 version.

Context if the expressions

Before we see the typical usage of XPath, we need to understand one of the most important fact: the context. For every expression its context determines the behavior. The processing takes two steps:

  1. static analysis:

    an operation tree is built based on the expression and its static context; it need to be normalized and after that a static type is assigned to the expression

  2. dynamic evaluation:

    the operation tree, the input data and the dynamic context used to determine the return value of the expression and a dynamic type is assigned to the expression

Context of an expression: contains the information which influences the result of the expression:

The XPath processing model

The XPath processing model basically based on the data model and the context of the expression. The model contains the following steps:

  1. Data model generation:

    • The XML parser generate an InfoSet - and using an optional validation, we can get an PSVI

    • this Infoset or PSVI is transformed to an XDM instance

  2. Scheme import's

  3. Expression evaluation:

    • static analysis

    • dynamic evaluation

  4. Serialization

This processing could be seen in the following figure:

Figure 5.1. The XPath processing model

The XPath processing model


Expressions

Expressions are form the base of XPath. With expressions we can identify different parts of an XML document. Its important to know that an expression could be processed in a given context only. The result of the expression could be in one of the four different types: node sequence, logical, textual or numerical.

Expressions could be divided into three big category: Path expressions, Value expressions and Sequence expressions. Path expressions are discussed in more details in the following section. The Value expressions are covering the primary expressions (literals, variable references, function calls) and arithmetic, logical and comparison expressions. The third group is discussed in the next part of the book because conditional, iteration and quantified expressions are more better placed in the XQuery section.

For the second group the following remarks are useful: String literals are defined by apostrophes or double quotes. Numbers are interpreted as double precision float pointing numbers. Variables are starting with the special dollar ($) sign which followed by a qualified name (QName). Variables could be any type from the supported XPath types. A function call is performed by the name with parenthesised arguments and those function names should be qualified names where each argument is an expression and the return value could be any supported value.

Steps

The XPath notation is very similar to the notation for file access by operating systems. Like the UNIX shell environment, the slash (/) is used for separating the steps in an expression. But this notation is used by the URL also, where the first part shows the primary resource and the following steps are identifying the further elements inside this resource.

In XPath the navigation inside the tree starts with the context node (the sequence of them). The navigational syntax is the following:

cs0/step

where cs0 (context sequence 0) denotes the context node sequence, from which a navigation in direction step is taken. It is a common error in XQuery expressions to try and start an XPath traversal without the context node sequence being actually defined. An XPath navigation may consist of multiple steps. Like the following example, step step1 starts off from the context node sequence cs0 and arrives at a sequence of new nodes cs1 . After that cs1 is used as the new context node sequence for step2 , and so on.

cs0/step1/step2/...
    ≡
((cs0/step1)/step2)/...
  '-------'
     cs1

Most of these expressions are locating different parts of an XML document. These parts are selected with one or more steps. Steps could be start as a Relative path starting from the context node or could be an absolute path which start with the slash (/) letter. One XPath location step is contains three parts:

ax :: nt [p1] ... [pN]
  1. axis (ax):

    the direction of navigation taken from the context nodes. It defines the relation of the context node and the selected nodes in the tree.

  2. node test (nt)

    which can be used to navigate to nodes of certain kind (e.g., only attribute nodes) or name.

  3. optional predicates (pi)

    which further filter the sequence of nodes we navigated to. The given node is only selected if all the predicates are evaluate to true.

The result of one step is always a set (exactly a sequence) of elements. During processing, it creates a set of elements based on the axis and the node test which further filtered by the predicates. The axis and the predicates could be omitted as well. The node test should contain names or meta characters - like the "*" which selects all the elements in the given context.

Axes

Inside the XPath expressions we can use several axes to select nodes. These axes are defining the selection directions relative to the context node. Axes are predicting the ways inside the tree. Practically, any node could be reach form any point form the tree with the help of these axes. The notation for them is the "::" operator after the name of the axe.

A 12 axes are the following:

Axe Description Direction Available nodes
child::

Contains the children of the context node.

Forward The children of a document node or element node may be element, processing instruction, comment, or text nodes. Attribute, namespace and document nodes can never appear as children.
parent::

Returns the parent of the context node, or an empty sequence if the context node has no parent

Reverse Element nodes.

Note:

An attribute node may have an element node as its parent, even though the attribute node is not a child of the element node.

descendant::

Defined as the transitive closure of the child axis; it contains the descendants of the context node.

Forward Element, processing instruction, comment, or text nodes.
ancestor:: Defined as the transitive closure of the parent axis; it contains the ancestors of the context node Reverse Element nodes.
descendant-or-self:: Contains the context node and the descendants of the context node Forward Attribute, namespace and document nodes can never appear.
ancestor-or-self Contains the context node and the ancestors of the context node; thus, the ancestor-or-self axis will always include the root node. Reverse Attribute, namespace and document nodes can never appear.
following:: Contains all nodes that are descendants of the root of the tree in which the context node is found, are not descendants of the context node, and occur after the context node in document order Forward Attribute, namespace and document root nodes can never appear.
preceding:: Contains all nodes that are descendants of the root of the tree in which the context node is found, are not ancestors of the context node, and occur before the context node in document order Reverse Attribute, namespace and document root nodes can never appear.
following-sibling:: Contains the context node's following siblings, those children of the context node's parent that occur after the context node in document order; if the context node is an attribute or namespace node, the following-sibling axis is empty. Forward Attribute, namespace and document root nodes can never appear.
preceding-sibling::

contains the context node's preceding siblings, those children of the context node's parent that occur before the context node in document order; if the context node is an attribute or namespace node, the preceding-sibling axis is empty.

Reverse Attribute, namespace and document root nodes can never appear.
attribute:: Contains the attributes of the context node. Forward Just attributes.
namespace:: Contains the namespace nodes of the context node. Forward Just namespaces.
self:: Contains just the context node itself. Could be any node.

These axes could be illustrated with the following figure:

Figure 5.2. XPath axes

XPath axes


XPath semantics:

  • The result node sequence of any XPath navigation is returned in document order with no duplicate nodes (recall node identity).

    (<a b="0"> 
    	<c d="1"><e>f</e></c>
    	<g><h/></g>
    </a>)/child::node()/parent::node()             => ( <a ..> ... </a> )
         /child::node()/following-sibling::node()  => ( <c d="1"><e>f</e></c> ,<g><h/></g> )
  • XPath semantic follows document order:

    (<a><b/><c/></a>,
    <d><e/><f/></d>)/child::node()         => (<b/>,<c/>,<e/>,<f/>)

    The XPath document order semantics require <b/> to occur before <c/> and <e/> to occur before <f/>. ( Naturally, the result (<e/>,<f/>,<b/>,<c/>) would have been OK as well.)

XPath Node test

Once an XPath step arrives at a sequence of nodes, we may apply a node test to filter nodes based on kind and name.

Kind Test Semantics
Node() Let any node pass.
Text() Preserve text nodes only.
Comment() Preserve comment nodes only.
Processing-instruction() Preserve processing instructions.
Processing-instruction(p) Preserve processing instructions of the form <?p…?>.
Document-node() Preserve the (invisible) document root node.

XPath Name test

A node test may also be a name test, preserving only those element or attribute nodes with matching names.

Name test Semantics
name Preserve element nodes with tag name only (for attribute axis: preserve attributes).
* Preserve element nodes with arbitrary tag names (for attribute axis: preserve attributes).

Note

Note: In general we will have cs/ax::* as a subset of cs/ax::Node().

Predicates

The optional third component of a step formulates a list of predicates [ p1 ] … [ pN ] against the nodes selected by an axis. These predicates are used to give further conditions to fulfill by the nodes.

Its important to underline that predicates have higher precedence than the XPath step operator (’/ ’sing):

cs/step[ p1 ][ p2 ] ≡ cs/((step[ p1 ])[ p2 ])

// The pi are evaluated left-to-right for each node in turn.
// In pi, the current context node 24 is available as ’.’ .
// Context item, actually: predicates may be applied to sequences of arbitrary items.

When using more than one predicate we can apply logical ( or, and, not ) and comparator (<, >, =, !=) operators as well.

/persons/person[@id or number]

// if we use a name inside a predicate without any operator or function, its existence is checked

Moreover, predicates could be nested into each other ( unlimited deeply).

/shop/items/item[price<2000 and stock[@available=true()]]

// Show all the items whose proce is lower than 2000 Ft and available in stock

Atomization

Atomization turns a sequence ( x1, …, xN ) of items into a sequence of atomic values ( v1,.., vN ):

  1. If xi is an atomic value, vi ≡ xi,

  2. if xi is a node, vi is the typed value of xi

Atomization could be implicit:

(<a>                                        (<b>42</b>,
    <b>42</b>                                <c><d>42</d></c>,
    <c><d>42</d></c>                    =>   <d>42</d>
    <e>43</e>                                )
</a>)/descendant-or-self::*[. eq 42]

or explicit:

(<a>
<b>42</b>
<c><d>42</d></c>
<e>43</e>
</a>)/descendant-or-self::*[data(.) cast as double eq 42 cast as double]

Positional access

Inside a predicate [p] the current context item is ’.’:

  • An expression may also access the position of ’.’ in the context sequence via position(). The first item is located at position 1.

  • Furthermore, the position of the last context item is available via last().

(x1, x2,...,xn )[position() eq i] => xi
(x1, x2,...,xn )[position() eq last()] => xn

A predicate of the form [position() eq i] with i being any XQuery expression of numeric type, may be abbreviated by [i].

Furthermore, it is important to remember back to precedence rule because the following example could result surprises:

// predicate [.] is stronger than a step (/)
// however, it is evaluated only after them
(cs/descendant-or-self::node()/child::x)[2]
vs.
cs/descendant-or-self::node()/child::x[2]

The context item: .

As a useful generalization, XPath makes the current context item ’.’ available in each step and not only in predicates. It means, in the expression cs/e the expression ’e’ will be evaluated with ’.’ set to each item in the context sequence cs (in order). The resulting sequence is returned.

Note: Remember: if e returns nodes (e has type node*), the resulting sequence is sorted in document order with duplicates removed.

(<a>1</a>,<b>2</b>,<c>3</c>)/(. + 42) => (43.0,44.0,45.0)
(<a>1</a>,<b>2</b>,<c>3</c>)/name(.)  => ("a","b","c")
(<a>1</a>,<b>2</b>,<c>3</c>)/position() => (1,2,3)
(<a><b/></a>)/(./child::b, .)           => (<a><b/></a>,<b/>)

Combining node sequences

XPath provides three operators to combine sequences: union (abbreviated as |), intersect and except. These operators remove duplicate nodes based on identity and return their result in document order. Note: We examine these expressions here because several useful query could be built on the top of them.

Selecting all x children and attributes of context node
cs/(./child::x | ./attribute::x)

Select all siblings of context node
cs/(./preceding-sibling::node() | ./following-sibling::node())
or
cs/(./parent::node()/child::node() except .)

Select context node and all its siblings
cs/(./parent::node()/child::node() | . )

First common ancestor
(cs0/ancestor::* intersect cs1/ancestor::*)[last()]

Abbreviations

Table 5.1. XPath Abbreviations

AbbreviationsExpansion
ntchild::nt
@attribute::
..parent::node()
///descendant-or-self::node()/
/root(.)
step./step


Examples:

a/b/c => ./child::a/child::b/child::c
a//@id => ./child::a/descendant-or-self::node()/attribute::id
//a => root(.)/descendant-or-self::node()/child::a
a/text() => ./child::a/child::text()

XPath 2.0 functions by categories

  • Accessors:

    • fn:node-name(node) – Returns an expanded-QName for node kinds that can have names.

    • fn:string(arg) – Returns the value of $arg represented as a xs:string. If no argument is supplied, the context item (.) is used as the default argument.

    • fn:data(item [, item,…]) – Takes a sequence of items and returns a sequence of atomic values.

  • Error Function: The fn:error function raises an error. While this function never returns a value, an error is returned to the external processing environment as an xs:anyURI or an xs:QName. The error xs:anyURI is derived from the error xs:QName.

    • fn:error(error, description, object) – Raising an exception.

  • Constructor Functions: Constructs object and atomic type instances.

    • xs:date(), xs:string(), xs:Name(), xs:token()

  • Numerics: As most of the programming languages, numeric functions made calculations and conversions on numbers. There are several built-in functuions and severek has abbreviated versions, like the „numeric-add” whichis backed up with the + symbol.

    • fn:round(num) - Rounding.

    • fn:abs(num) – Absolute value.

    • fn:number(arg) – Converts a string liter into a number.

  • Functions on Strings: Almost operates on strings and returns a string value but not all of the cases.

    • fn:concat(string [, string..]) – Concatenates two or more xs:anyAtomicType arguments cast to xs:string.

    • fn:string-length([ | string]) – Returns an xs:integer equal to the length in characters of the value of $arg or if empty, it returns the length of the context item.

    • fn:starts-with(string1, string2)/ fn:ends-with(string1, string2)

    • fn:contains(string1, string2)

    • fn:replace(string, pattern, replace)

  • URI functions: Operates with URI. The only one function in this category:

    • fn:resolve-uri(relative, base) – resolve a relative URI into an absolute.

  • Boolean functions

    • fn:boolean(arg) – String, numeric or nodes effective boolean value. Note: (), 0, NaN, "" and false() evaluates to false()!

    • fn:not(arg) – Inverts the xs:boolean value of the argument.

  • Functions and Operators on Durations, Dates and Times

    • fn:dateTime(date, time) – returns a TimeStamp object.

    • fn:year-from-date(date) – The duration from the given year. It exists in the form of months and dates as well.

    • fn:hours-from-time(time) - Same as above just measured in hours.

    • fn:adjust-dateTime-to-timezone(datetime, timezone) – Converts a timestamp object to the given time zone.

      • There are functions to add, extract and compare dates too.

  • Functions Related to QNames (Qualified Name): QName represents XML qualified names. The value space of QName is the set of tuples {namespace name, local part}, where namespace name is an anyURI and local part is an NCName.

    • fn:QName() – Returns an xs:QName with the namespace URI given in the first argument and the local name and prefix in the second argument.

    • fn:local-name-from-QName() – Returns an xs:NCName representing the local name of the xs:QName argument.

    • fn:namespace-uri-from-QName() – Returns the namespace URI for the xs:QName argument. If the xs:QName is in no namespace, the zero-length string is returned.

  • Nodeset functions:

    • fn:name([nodeset]) – The name of the actual node or the first element"s in a sequence.

    • fn:root([node]) – Returns the root node.

    • op:is-same-node – True if the two nodes are the same.

  • Sequence functions: A sequence is an ordered collection of zero or more items. An item is either a node or an atomic value.

    • fn:count(collection) - Returns the number of items in a sequence.

    • fn:max(collection) - Returns the maximum value from a sequence of comparable values.

    • fn:avg(collection) – Returns the average of a sequence of values.

    • fn:empty(collection) – True if the sequence is empty.

    • fn:exists(collection) – True if the sequence is not empty.

  • Context functions: The following functions are defined to obtain information from the dynamic context.

    • fn:last() –Returns the number of items in the sequence of items currently being processed.

    • fn:current-date()/fn:current-time() – returns the current xs:dateTime or xs:time.

    • fn:implicit-timezone() – Returns the value of the implicit timezone property from the dynamic context.

  • Other functions: Operators on base64Binary and hexBinary, Operators on NOTATION.