4.1. XPath expression components

An XPath expression is composed of steps separated by /. Each step designates an axis which can be understood as the direction in which the nodes will be collected from the current node (called here the starting node) in the document tree. An axis is a predefined name followed by :: (Figure 4.1 some examples of axes). The axis specification is followed by a node test which is often the name of a node or * to indicate any element. The node(s) thus specified can be further restricted with a predicate expression within square brackets; this is a boolean expression evaluated at each node, which is kept in the result sequence if it evaluates to true; it can also be a positive integer in which case the sequence only keeps the node with this index.

Using the instance document shown in Example D.1 (page ), here are a few examples of XPath expressions:

This notation is very powerful but a bit tedious to write so XPath designers have defined an abbreviated syntax for the most frequent cases: child:: can be omitted, attribute:: can be written as @ and descendant:: is written as //. This notation is thus similar to what is used in computer systems to designate files and directories; except that at each step (i.e. between slashes) many nodes can be selected instead of only one file or directory. The above examples can thus be simplified as

Figure 4.1. Some XPath axes

Some XPath axes

Given a document tree rooted at node 1 and a starting node indicated by node 6 (in grey), the rounded rectangles wrap the sequence of nodes in some XPath axes. The attribute:: axis is not shown here because it would be within the grey node.


After this quick overview of XPath, we give some more details on the evaluation of its expressions, which is at the root of XSLT. We remind the reader of the seven types of nodes in an XML document:

root

the starting point of the document

element

the most common type of node, it may contain other elements

text

containing the real information; it cannot contain any element

attribute

string information contained in the start-tag of the containing element, it is considered a child of the element which contains it

comment

information that is normally ignored for processing but that is nevertheless kept in the structure of the document

processing instruction

elements starting with <? that will not be discussed in this document

namespace

information about the namespace of an element, its processing will not be discussed in this section.

An XPath expression designating a sequence of nodes in the document tree consists of three parts.

  1. an axis specifier gives the path to a set of nodes. Most of the time, we can use the abbreviated syntax.

  2. a node test can be the name of a node (with or without the namespace prefix), * to indicate all elements, or it can be a function name such as node(), text() or comment() to indicate the type of the node that is sought.

  3. a predicate is a boolean expression given between square brackets ([]) that can further filter the set of nodes identified with the axis specifier and the node test. If the expression is a number i, then it refers to the ith child element (numbering starts at 1).

The following grammar gives the rules of an XPath expression as taken from the XPath standard [6]. Terminals are shown in monospace font. As an extended BNF notation (EBNF) is used, some terminals such as parenthesis, star, plus or vertical bar are used for grouping, to indicate repetition and alternation. There are essentially the same symbols as the ones used in DTD or Relax NG compact notation. When a symbol of the EBNF also occurs as a terminal, it is enclosed within angle quotes (« »).

Similarly to other functional programming languages, XPath defines an expression in terms of a sequence of one or more expressions [rule 2]. The comma (,) operator is used to create a sequence out of two sequences which are concatenated; sequences of sequences are not allowed.

The building blocks of an XPath expressions are the following:

XPath 2.0 grammar
[1] XPath ::= Expr  
[2] Expr ::= ExprSingle ("," ExprSingle)*  
[3] ExprSingle ::= ForExpr
| QuantifiedExpr
| IfExpr
| OrExpr
 
[4] ForExpr ::= SimpleForClause "return" ExprSingle  
[5] SimpleForClause ::= "for" "$" VarName "in" ExprSingle ("," "$" VarName "in" ExprSingle)*  
[6] QuantifiedExpr ::= ("some" | "every") "$" VarName "in" ExprSingle
("," "$" VarName "in" ExprSingle)* "satisfies" ExprSingle
 
[7] IfExpr ::= "if" "(" Expr ")" "then" ExprSingle "else" ExprSingle  
[8] OrExpr ::= AndExpr ( "or" AndExpr )*  
[9] AndExpr ::= ComparisonExpr ( "and" ComparisonExpr )*  
[10] ComparisonExpr ::= RangeExpr ( (ValueComp | GeneralComp | NodeComp) RangeExpr )?  
[11] RangeExpr ::= AdditiveExpr ( "to" AdditiveExpr )?  
[12] AdditiveExpr ::= MultiplicativeExpr ( ("+" | "-") MultiplicativeExpr )*  
[13] MultiplicativeExpr ::= UnionExpr ( ("*" | "div" | "idiv" | "mod") UnionExpr )*  
[14] UnionExpr ::= IntersectExceptExpr ( ("union" | "|") IntersectExceptExpr )*  
[15] IntersectExceptExpr ::= InstanceofExpr ( ("intersect" | "except") InstanceofExpr )*  
[16] InstanceofExpr ::= TreatExpr ( "instance" "of" SequenceType )?  
[17] TreatExpr ::= CastableExpr ( "treat" "as" SequenceType )?  
[18] CastableExpr ::= CastExpr ( "castable" "as" SingleType )?  
[19] CastExpr ::= UnaryExpr ( "cast" "as" SingleType )?  
[20] UnaryExpr ::= ("-" | "+")* ValueExpr  
[21] ValueExpr ::= PathExpr  
[22] GeneralComp ::= "=" | "!=" | "<" | "<=" | ">" | ">="  
[23] ValueComp ::= "eq" | "ne" | "lt" | "le" | "gt" | "ge"  
[24] NodeComp ::= "is" | "<<" | ">>"  
[25] PathExpr ::= ("/" RelativePathExpr?)
| ("//" RelativePathExpr)
| RelativePathExpr
 
[26] RelativePathExpr ::= StepExpr (("/" | "//") StepExpr)*  
[27] StepExpr ::= FilterExpr | AxisStep  
[28] AxisStep ::= (ReverseStep | ForwardStep) PredicateList  
[29] ForwardStep ::= (ForwardAxis NodeTest) | AbbrevForwardStep  
[30] ForwardAxis ::= ("child" "::") | ("descendant" "::") | ("attribute" "::") | ("self" "::")
| ("descendant-or-self" "::") | ("following-sibling" "::")
| ("following" "::") | ("namespace" "::")
 
[31] AbbrevForwardStep ::= "@"? NodeTest  
[32] ReverseStep ::= (ReverseAxis NodeTest) | AbbrevReverseStep  
[33] ReverseAxis ::= ("parent" "::") | ("ancestor" "::") | ("preceding-sibling" "::")
| ("preceding" "::") | ("ancestor-or-self" "::")
 
[34] AbbrevReverseStep ::= ".."  
[35] NodeTest ::= KindTest | NameTest  
[36] NameTest ::= QName | Wildcard  
[37] Wildcard ::= "*" | (NCName ":" "*") | ("*" ":" NCName)  
[38] FilterExpr ::= PrimaryExpr PredicateList  
[39] PredicateList ::= Predicate*  
[40] Predicate ::= "[" Expr "]"  
[41] PrimaryExpr ::= Literal | VarRef | ParenthesizedExpr | ContextItemExpr | FunctionCall  
[42] Literal ::= NumericLiteral | StringLiteral  
[43] NumericLiteral ::= IntegerLiteral | DecimalLiteral | DoubleLiteral  
[44] VarRef ::= "$" VarName  
[45] VarName ::= QName  
[46] ParenthesizedExpr ::= "(" Expr? ")"  
[47] ContextItemExpr ::= "."  
[48] FunctionCall ::= QName "(" (ExprSingle ("," ExprSingle)*)? ")"  
[49] SingleType ::= AtomicType "?"?  
[50] SequenceType ::= ("empty-sequence" "(" ")") | (ItemType OccurrenceIndicator?)  
[51] OccurrenceIndicator ::= "?" | "*" | "+"  
[52] ItemType ::= KindTest | ("item" "(" ")") | AtomicType  
[53] AtomicType ::= QName  
[54] KindTest ::= DocumentTest | ElementTest | AttributeTest
| SchemaElementTest | SchemaAttributeTest | PITest
| CommentTest | TextTest | AnyKindTest
 
[55] AnyKindTest ::= "node" "(" ")"  
[56] DocumentTest ::= "document-node" "(" (ElementTest | SchemaElementTest)? ")"  
[57] TextTest ::= "text" "(" ")"  
[58] CommentTest ::= "comment" "(" ")"  
[59] PITest ::= "processing-instruction" "(" (NCName | StringLiteral)? ")"  
[60] AttributeTest ::= "attribute" "(" (AttribNameOrWildcard ("," TypeName)?)? ")"  
[61] AttribNameOrWildcard ::= AttributeName | "*"  
[62] SchemaAttributeTest ::= "schema-attribute" "(" AttributeDeclaration ")"  
[63] AttributeDeclaration ::= AttributeName  
[64] ElementTest ::= "element" "(" (ElementNameOrWildcard ("," TypeName "?"?)?)? ")"  
[65] ElementNameOrWildcard ::= ElementName | "*"  
[66] SchemaElementTest ::= "schema-element" "(" ElementDeclaration ")"  
[67] ElementDeclaration ::= ElementName  
[68] AttributeName ::= QName  
[69] ElementName ::= QName  
[70] TypeName ::= QName