View Old View New View Both View Only Previous Next

This draft contains only sections that have differences from the version that it modified.

W3C

XML Path Language (XPath) 4.0 WG Review Draft

W3C Editor's Draft 23 February 2026

This version:
https://qt4cg.org/specifications/xpath-40/
Most recent version of XPath:
https://qt4cg.org/specifications/xpath-40/
Most recent Recommendation of XPath:
https://www.w3.org/TR/2017/REC-xpath-31-20170321/
Editor:
Michael Kay, Saxonica <mike@saxonica.com>

Please check the errata for any errors or issues reported since publication.

See also translations.

This document is also available in these non-normative formats: XML.


Abstract

XPath 4.0 is an expression language that allows the processing of values conforming to the data model defined in [XQuery and XPath Data Model (XDM) 4.0]. The name of the language derives from its most distinctive feature, the path expression, which provides a means of hierarchic addressing of the nodes in an XML tree. As well as modeling the tree structure of XML, the data model also includes atomic items, function items, maps, arrays, and sequences. This version of XPath supports JSON as well as XML, and adds many new functions in [XQuery and XPath Functions and Operators 4.0].

XPath 4.0 is a superset of XPath 3.1. A detailed list of changes made since XPath 3.1 can be found in I Change Log.

Status of this Document

This is a draft prepared by the QT4CG (officially registered in W3C as the XSLT Extensions Community Group). Comments are invited.

Dedication

The publications of this community group are dedicated to our co-chair, Michael Sperberg-McQueen (1954–2024).

Michael was central to the development of XML and many related technologies. He brought a polymathic breadth of knowledge and experience to everything he did. This, combined with his indefatigable curiosity and appetite for learning, made him an invaluable contributor to our project, along with many others. We have lost a brilliant thinker, a patient teacher, and a loyal friend.


4 Expressions

This section discusses each of the basic kinds of expression. Each kind of expression has a name such as PathExpr, which is introduced on the left side of the grammar production that defines the expression. Since XPath 4.0 is a composable language, each kind of expression is defined in terms of other expressions whose operators have a higher precedence. In this way, the precedence of operators is represented explicitly in the grammar.

The order in which expressions are discussed in this document does not reflect the order of operator precedence. In general, this document introduces the simplest kinds of expressions first, followed by more complex expressions. For the complete grammar, see Appendix [A XPath 4.0 Grammar].

The highest-level symbol in the XPath grammar is XPath.

XPath::=Expr
Expr::=(ExprSingle ++ ",")
ExprSingle::=ForExpr
| LetExpr
| QuantifiedExpr
| IfExpr
| OrExpr
ExprSingle::=ForExpr
| LetExpr
| QuantifiedExpr
| IfExpr
| OrExpr
ForExpr::=ForClauseForLetReturn
LetExpr::=LetClauseForLetReturn
QuantifiedExpr::=("some" | "every") (QuantifierBinding ++ ",") "satisfies" ExprSingle
IfExpr::="if" "(" Expr ")" (UnbracedActions | BracedAction)
OrExpr::=AndExpr ("or" AndExpr)*

The XPath 4.0 operator that has lowest precedence is the comma operator, which is used to combine two operands to form a sequence. As shown in the grammar, a general expression (Expr) can consist of multiple ExprSingle operands, separated by commas.

The name ExprSingle denotes an expression that does not contain a top-level comma operator (despite its name, an ExprSingle may evaluate to a sequence containing more than one item.)

The symbol ExprSingle is used in various places in the grammar where an expression is not allowed to contain a top-level comma. For example, each of the arguments of a function call must be a ExprSingle, because commas are used to separate the arguments of a function call.

After the comma, the expressions that have next lowest precedence are ForExpr, LetExpr, QuantifiedExpr, IfExpr, and OrExpr. Each of these expressions is described in a separate section of this document.

4.5 Functions

Functions in XPath 4.0 arise in two ways:

The functions defined by a statically known function definition can be invoked using a static function call. Function items corresponding to these definitions can also be obtained, as dynamic values, by evaluating a named function reference. Function items can also be obtained using the fn:function-lookup function: in this case the function name and arity do not need to be known statically, and the function definition need not be present in the static context, so long as it is in the dynamic context.

Static and dynamic function calls are described in the following sections.

4.5.6 Inline Function Expressions

Changes in 4.0  

  1. In inline function expressions, the keyword function may be abbreviated as fn.   [Issue 1192 PR 1197 21 May 2024]

  2. New abbreviated syntax is introduced (focus function) for simple inline functions taking a single argument. An example is fn { ../@code }  [Issue 503 PR 521 30 May 2023]

InlineFunctionExpr::=MethodAnnotation* ("function" | "fn") FunctionSignature? FunctionBody
MethodAnnotation::="%method"
FunctionSignature::="(" ParamList ")" TypeDeclaration?
ParamList::=(VarNameAndType ** ",")
VarNameAndType::="$" EQNameTypeDeclaration?
EQName::=QName | URIQualifiedName
TypeDeclaration::="as" SequenceType
SequenceType::=("empty-sequence" "(" ")")
| (ItemTypeOccurrenceIndicator?)
FunctionBody::=EnclosedExpr
EnclosedExpr::="{" Expr? "}"

[Definition: An inline function expression, when evaluated, creates an anonymous function defined directly in the inline function expression.] An inline function expression specifies the names and SequenceTypes of the parameters to the function, the SequenceType of the result, and the body of the function.

An inline function expression whose FunctionSignature is omitted is known as a focus function. Focus functions are described in 4.5.6.2 Focus Functions.

[Definition: An anonymous function is a function item with no name. Anonymous functions may be created, for example, by evaluating an inline function expression or by partial function application.]

The keywords function and fn are synonymous.

The syntax allows the names and types of the function argument to be declared, along with the type of the result:

function($x as xs:integer, $y as xs:integer) as xs:integer { $x + $y }

The types can be omitted, and the keyword can be abbreviated:

fn($x, $y) { $x + $y }

A zero-arity function can be written as, for example, fn() { current-date() }.

If a function parameter is declared using a name but no type, its default type is item()*. If the result type is omitted, its default result type is item()*.

The parameters of an inline function expression are considered to be variables whose scope is the function body. It is a static error [err:XQST0039] for an inline function expression to have more than one parameter with the same name.

The annotation keyword %method is described in 4.5.6.1 Methods.

The static context for the function body is inherited from the location of the inline function expression, with the exception of the static type of the context value which is initially absentDM.

The variables in scope for the function body include all variables representing the function parameters, as well as all variables that are in scope for the inline function expression. If the annotation %method is present then an additional system-defined variable $this is added to the static context for the function body, as described in 4.5.6.1 Methods.

Note:

Function parameter names can mask variables that would otherwise be in scope for the function body.

The result of an inline function expression is a single function item with the following properties (as defined in Section 7.1 Function ItemsDM):

  • name: Absent.

  • identity: A new function identity distinct from the identity of any other function item.

  • parameter names: The parameter names in the InlineFunctionExpr’s ParamList.

  • signature: A FunctionType constructed from the SequenceTypes in the InlineFunctionExpr. An implementation which can determine a more specific signature (for example, through use of type analysis of the function’s body) is permitted to do so.

  • annotations: If the keyword %method is present, then a list containing a single annotation whose name is a QName with local name "method" and namespace "http://www.w3.org/2012/xquery" and whose value is an empty sequence; otherwise an empty set..

  • body: The FunctionBody of the InlineFunctionExpr.

  • captured context: the static context is the static context of the inline function expression, with the exception of the static context value type which is absentDM. The dynamic context has an absent focus, and a set of variable bindings comprising the variable values component of the dynamic context of the InlineFunctionExpr.

The following are examples of some inline function expressions:

  • This example creates a function that takes no arguments and returns a sequence of the first 6 primes:

    function() as xs:integer+ { 2, 3, 5, 7, 11, 13 }
  • This example creates a function that takes two xs:double arguments and returns their product:

    fn($a as xs:double, $b as xs:double) as xs:double { $a * $b }
  • This example creates and invokes a function that captures the value of a local variable in its scope:

    let $incrementors := (
      for $x in 1 to 10
      return function($y) as xs:integer { $x + $y }
    )
    return $incrementors[2](4)

    The result of this expression is 6

4.5.6.1 Methods

[Definition: A method is a function item that has the annotation %method.]

A method contained in a map can refer to the containing map using the special variable $this. For example, given the variable:

let $rectangle := { 'height': 3,
                    'width': 4,
                    'area': %method fn() { $this?height * $this?width }
                  }
let $rectangle := { 'height': 3,
                    'width': 4,
                    'area': %method fn() { $this?height × $this?width }
                  }

The dynamic function call $rectangle?area() returns 12.

The detailed rules are as follows:

  1. The function item created by an inline function expression with the annotation %method (referred to as a method) has an additional parameter named $this (in no namespace), which precedes all user-declared parameters. The static type of this parameter is map(*). In consequence, the variable name $this is in scope within the body of the method.

  2. When the lookup operator ? or ?? is applied to a map M (see 4.13.3 Lookup Expressions), and selects a key/value pair whose value part is a singletonmethodF, the function item that is returned by the lookup expression is a partial application of F that binds the implicit parameter $this to the map M. This function item has no %method annotation and is therefore not a method.

Note:

Methods are typically invoked using a dynamic function call such as the call $rectangle?area() in the example above. In addition, a method selected using a lookup expression such as $rectangle?area can be used in the same way as any other function item. For example, it can be passed as an argument to a higher-order function, or it can be partially applied.

Although methods mimic some of the capability of object-oriented languages, the functionality is more limited:

  • There is no encapsulation: the entries in a map are all publicly exposed.

  • There is no class hierarchy, and no inheritance or overriding.

  • Methods within a map can be removed or replaced in the same way as any other entries in the map.

The $this variable in the body of a method is bound to the containing map by any lookup expression (using the ? or ?? operators) that selects the method as a singleton item within a key/value pair. It is not bound by other operations that deliver the value, for example a call on map:get or map:for-each. When $this is bound to a map, the result is not itself a method. The means, for example that the expression:

let $rectangle1 := { 'x':3, 'y':4, 'area': %method fn() {$this?x * $this?y} }
let $rectangle2 := { 'x':5, 'y':5, 'area': $rectangle1?area }
return $rectangle2?area()
let $rectangle1 := { 'x':3, 'y':4, 'area': %method fn() {$this?x × $this?y} }
let $rectangle2 := { 'x':5, 'y':5, 'area': $rectangle1?area }
return $rectangle2?area()

returns 12, because the function item bound to the key "area" in $rectangle2 is an ordinary function item, not a method.

If the same method is to be used in both variables, this can be written:

let $area := %method fn() {$this?x * $this?y}                     
let $rectangle1 := { 'x':3, 'y':4, 'area': $area }
let $rectangle2 := { 'x':5, 'y':5, 'area': $area }
return $rectangle2?area()
let $area := %method fn() {$this?x × $this?y}                     
let $rectangle1 := { 'x':3, 'y':4, 'area': $area }
let $rectangle2 := { 'x':5, 'y':5, 'area': $area }
return $rectangle2?area()

which returns 25.

In the case of a method that defines explicit parameters (beyond the implicit $this parameter), it is also possible to invoke the method using an arrow expression (see 4.20 Arrow Expressions). For example, the following code constructs a rectangle with height 6 and width 8:

                  
let $rectangle := { 'height': 3,
                    'width': 4,
                    'expand': %method fn($ratio) { 
                       { 'height': $this?height × $ratio,
                         'width': $this?width × $ratio,
                         'expand': map:get($this, 'expand') }
                  }
return 2 => $rectangle?expand()

Note the use of map:get($this, 'expand') here in preference to $this?expand. Using map:get ensures that the expand method is not partially applied, which would bind the value of $this to the wrong rectangle.

Since a method is a function item with an implicitly declared parameter named $this, it is also possible to invoke it directly. The method %method fn() {$this?x * $this?y} is equivalent to the function item fn($this as map(*)) {$this?x * $this?y}, which means it may be invoked using a call such as:

let $area := %method fn() {$this?x * $this?y}                     
return $area( { 'x':3, 'y':4 } )
let $area := %method fn() {$this?x × $this?y}                     
return $area( { 'x':3, 'y':4 } )

The following syntax is equivalent:

let $area := %method fn() {$this?x × $this?y}                     
return { 'x':3, 'y':4 } => $area()

Note:

Methods can be useful when there is a need to write inline recursive functions. For example:

let $lib := {
   'product': %method fn($in as xs:double*) {
                        if (empty( $in ))
                        then 1
                        else head( $in ) * $this?product( tail($in) )
                      }
}
return $lib?product( (1.2, 1.3, 1.4) )
let $lib := {
   'product': %method fn($in as xs:double*) {
                        if (empty( $in ))
                        then 1
                        else head( $in ) × $this?product( tail($in) )
                      }
}
return $lib?product( (1.2, 1.3, 1.4) )

In an environment that supports XPath but not XQuery, this mechanism can be used to define all the functions that a particular XPath expression needs to invoke, and these functions can be mutually recursive.