This document is also available in these non-normative formats: XML.
Copyright © 2000 W3C® (MIT, ERCIM, Keio, Beihang). W3C liability, trademark and document use rules apply.
XML is a versatile markup language, capable of labeling the information content of diverse data sources, including structured and semi-structured documents, relational databases, and object repositories. A query language that uses the structure of XML intelligently can express queries across all these kinds of data, whether physically stored in XML or viewed as XML via middleware. This specification describes a query language called XQuery, which is designed to be broadly applicable across many types of XML data sources.
A list of changes made since XQuery 3.1 can be found in J Change Log.
This section describes the status of this document at the time of its publication. Other documents may supersede this document.
This document is a working draft developed and maintained by a W3C Community Group, the XQuery and XSLT Extensions Community Group unofficially known as QT4CG (where "QT" denotes Query and Transformation). This draft is work in progress and should not be considered either stable or complete. Standard W3C copyright and patent conditions apply.
The community group welcomes comments on the specification. Comments are best submitted as issues on the group's GitHub repository.
The community group maintains two extensive test suites, one oriented to XQuery and XPath, the other to XSLT. These can be found at qt4tests and xslt40-test respectively. New tests, or suggestions for correcting existing tests, are welcome. The test suites include extensive metadata describing the conditions for applicability of each test case as well as the expected results. They do not include any test drivers for executing the tests: each implementation is expected to provide its own test driver.
The publications of this community group are dedicated to our co-chair, Michael Sperberg-McQueen (1954–2024).
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 XQuery 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 XQuery 4.0 Grammar].
[Definition: A query consists of one or more modules.] If a query is executable, one of its modules has a Query Body containing an expression whose value is the result of the query. An expression is represented in the XQuery grammar by the symbol Expr.
Expr | ::= | (ExprSingle ++ ",") |
ExprSingle | ::= | FLWORExpr |
ExprSingle | ::= | FLWORExpr |
FLWORExpr | ::= | InitialClauseIntermediateClause* ReturnClause |
QuantifiedExpr | ::= | ("some" | "every") (QuantifierBinding ++ ",") "satisfies" ExprSingle |
SwitchExpr | ::= | "switch" SwitchComparand (SwitchCases | BracedSwitchCases) |
TypeswitchExpr | ::= | "typeswitch" "(" Expr ")" (TypeswitchCases | BracedTypeswitchCases) |
IfExpr | ::= | "if" "(" Expr ")" (UnbracedActions | BracedAction) |
TryCatchExpr | ::= | TryClause ((CatchClause+ FinallyClause?) | FinallyClause) |
OrExpr | ::= | AndExpr ("or" AndExpr)* |
The XQuery 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 FLWORExpr,QuantifiedExpr, SwitchExpr, TypeswitchExpr, IfExpr, TryCatchExpr, and OrExpr. Each of these expressions is described in a separate section of this document.
Functions in XQuery 4.0 arise in two ways:
A function definition contains information about a family of functions with the same name and a defined arity range. These functions are in most cases known statically (they appear in the statically known function definitions), but there may be further function definitions that are known only dynamically (appearing in the dynamically known function definitions).
Function items are XDM items that can be called using a dynamic function call. They are values that can be bound to variables, passed as arguments, returned as function results, and generally manipulated in the same way as other XDM values.
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.
A dynamic function call consists of a base expression that returns the function and a parenthesized list of zero or more arguments (argument expressions or ArgumentPlaceholders).
A dynamic function call is evaluated as described in 4.5.3.1 Evaluating Dynamic Function Calls.
The following are examples of dynamic function calls:
This example calls the function contained in $f, passing the arguments 2 and 3:
$f(2, 3)
This example fetches the second item from sequence $f, treats it as a function and calls it, passing an xs:string argument:
$f[2]("Hi there")This example calls the function $f passing no arguments, and filters the result with a positional predicate:
$f()[2]
Note:
Arguments in a dynamic function call are always supplied positionally.
A dynamic function call can now be applied to a sequence of functions, and in particular to an empty sequence. This makes it easier to chain a sequence of calls. [Issue 1240 ]
This section applies to dynamic function calls whose arguments do not include an ArgumentPlaceholder. For function calls that include a placeholder, see 4.5.4 Partial Function Application.
A dynamic function call is an expression that is evaluated by calling a function item, which is typically obtained dynamically.
When a dynamic function call FC is evaluated, the result is obtained as follows:
The base expression of the function call is evaluated. If this is not of type function(*)* (a sequence of zero or more function items) then a type error is raised [err:XPTY0004].
The result of the dynamic function call is the sequence concatenation of the results of applying each function item individually, retaining order. That is, the result of F(X, Y, ...) is for $FI in F return $FI(X, Y, ...). The result of a dynamic function call applied to a single function item FI is defined by the rules that follow.
[err:XPTY0004]. If the arity of FI does not match the number of arguments in the ArgumentList, a type error is raised [err:XPTY0004].
Argument expressions are evaluated, producing argument values. The order of argument evaluation is implementation-dependent and an argument need not be evaluated if the function body can be evaluated without evaluating that argument.
Each argument value is converted to the corresponding parameter type in FI’s signature by applying the coercion rules, resulting in a converted argument value
If FI is a map, it is evaluated as described in 4.14.1.2 Maps as Functions.
If FI is an array, it is evaluated as described in 4.14.2.2 Arrays as Functions.
If FI’s body is an XQuery 4.0 expression (for example, if FI is a user-defined function or an anonymous function, or a partial application of such a function):
FI’s body is evaluated. The static context for this evaluation is the static context of the XQuery 4.0 expression. The dynamic context for this evaluation is obtained by taking the dynamic context of the module that contains the FunctionBody, and making the following changes:
The focus (context value, context position, and context size) is absentDM.
In the variable values component of the dynamic context, each converted argument value is bound to the corresponding parameter name.
When this is done, the converted argument values retain their dynamic types, even where these are subtypes of the declared parameter types. For example, a function with a parameter $p of type xs:decimal can be called with an argument of type xs:integer, which is derived from xs:decimal. During the processing of this function call, the value of $p inside the body of the function retains its dynamic type of xs:integer.
FI’s nonlocal variable bindings are also added to the variable values. (Note that the names of the nonlocal variables are by definition disjoint from the parameter names, so there can be no conflict.)
The value returned by evaluating the function body is then converted to the declared return type of FI by applying the coercion rules. The result is then the result of evaluating FC.
As with argument values, the value returned by a function retains its dynamic type, which may be a subtype of the declared return type of FI. For example, a function that has a declared return type of xs:decimal may in fact return a value of dynamic type xs:integer.
If the implementation of FI is not an XQuery 4.0 expression (for example, if FI is a system functionor an external function), the body of the function is evaluated, and the result is converted to the declared return type, in the same way as for a static function call (see 4.5.1.1 Static Function Call Syntax).
Errors may be raised in the same way.
$incr is a nonlocal variable that is available within the function because its variable binding has been added to the variable values of the function. Even though the parameter and return type of this function are both xs:decimal, the more specific type xs:integer is preserved in both cases.
let $incr := 1
let $f := function($i as xs:decimal) as xs:decimal { $i + $incr }
return $f(5)
The following example will raise a type error [err:XPDY0002]:
let $vat := function() { @vat + @price }
return doc('wares.xml')/shop/article/$vat()Instead, the context value can be used as an argument to the anonymous function:
let $vat := function($art) { $art/@vat + $art/@price }
return doc('wares.xml')/shop/article/$vat(.)Alternatively, the value can be referenced as a nonlocal variable binding:
let $ctx := doc('wares.xml')/shop/article
let $vat := function() { for $a in $ctx return $a/@vat + $a/@price }
return $vat()Finally, a focus function can be used. This binds the value of the argument to the context value within the function body:
let $vat := function { @vat + @price }
return $vat(doc('wares.xml')/shop/article)
A dynamic function call can call zero or more functions with the same arguments, returning the sequence concatenation of the result. For example:
(abs#1, round#1, floor#1, ceiling#1)(3.2)returns the sequence (3.2, 3, 3, 4).
A common case for supplying a sequence of functions arises when the functions are arrays. For example:
csv-to-arrays( string-join(("a,b,c", "p,q,r", "x,y,z"), char(10)) ) (2)returns the sequence ("b", "q", "y").
If the base expression evaluates to an empty sequence, the result is an empty sequence.
Note:
Keyword arguments are not allowed in a dynamic function call.
Most modern programming languages have support for collections of key/value pairs, which may be called maps, dictionaries, associative arrays, hash tables, keyed lists, or objects (these are not the same thing as objects in object-oriented systems). In XQuery 4.0, we call these maps. Most modern programming languages also support ordered lists of values, which may be called arrays, vectors, or sequences. In XQuery 4.0, we have both sequences and arrays. Unlike sequences, an array is an item, and can appear as an item in a sequence.
Note:
The XQuery 4.0 specification focuses on syntax provided for maps and arrays, especially constructors and lookup.
Some of the functionality typically needed for maps and arrays is provided by functions defined in [Functions and Operators 4.0] section 14 Processing maps and [Functions and Operators 4.0] section 15 Processing arrays, including functions used to read JSON to create maps and arrays, serialize maps and arrays to JSON, combine maps to create a new map, remove map entries to create a new map, iterate over the keys of a map, convert an array to create a sequence, combine arrays to form a new array, and iterate over arrays in various ways.
A method call invokes a function held as the value of an entry in a map, supplying the map implicitly as the value of the first argument. [Issue 2143 4 August 2025]
A method call combines accessing a map M to look up an entry whose value is a function item F, and calling the function item F supplying the map M as the implicit value of the first argument.
For example, given the variable:
let $rectangle := {
'height': 3,
'width': 4,
'area': fn ($rect) {
$rect?height × $rect?width
},
'perimeter': fn ($rect) {
2 × ($rect?height + $rect?width)
},
'resize': fn ($rect, $factor) {
$rect
=> map:put('height', $rect?height × $factor)
=> map:put('width', $rect?width × $factor)
}
}The method call $rectangle =?> area() returns 12, while the method call $rectangle =?> perimeter() returns 14, and $rectangle =?> resize(2) returns a map representing a rectangle with height = 6 and width = 8.
An arity-one function can also be written as a focus function:
let $rectangle := {
'height': 3,
'width': 4,
'area': fn { ?height × ?width }
}The expression M =?> N(X, Y, ...) is by definition equivalent to:
for $map as map(*) in M let $f as function(*) := $map?N return $f($map, X, Y, ...)
(where $map and $f are otherwise unused variable names).
Note:
The left-hand operand can be a sequence of maps. For example, given $rectangle defined as in the first example above, the expression ((1 to 2) ! $rectangle =?> resize(.)) =?> area() returns the sequence (12, 48).
The argument list in a method call must not include an argument placeholder; that is, the call must not be a partial function application ([err:XPST0003]).
Note:
Implicit in this definition are the following rules:
The value of M must be a sequence of zero or more maps;
Each of those maps must have an entry with the key N (as an instance of xs:string, xs:untypedAtomic, or xs:anyURI);
The value of that entry must be a single function item;
That function item must have an arity equal to one plus the number of supplied arguments, and the signature of the function must allow a map to be supplied as the first argument.
The error codes raised if these conditions are not satisfied are exactly the same as if the expanded code were used directly.
Note:
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.
Note:
Methods can be useful when there is a need to write inline recursive functions. For example:
let $lib := {
'product': fn($map as map(*), $in as xs:double*) {
if (empty( $in ))
then 1
else head($in) × $map =?> 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.
Note:
Methods are often useful in conjunction with named record types: see 5.20.3 Using Methods in Records.
In the example above, $rectangle =?> area(), $rectangle is typically a single map, and area is the key of one of the entries in the map, the value of the entry being a function item that takes the map as its implicit first argument. The method call $rectangle =?> area() first performs a map lookup ($rectangle?area) to select the function item, and then calls the function item, supplying the containing map as the first (and in this case only) argument.
Such calls can be chained. For example, $rectangle =?> resize(2) returns a rectangle that is twice the size of the original, so $rectangle =?> resize(2) =?> area() returns the area of the enlarged rectangle.
Note:
Note how the resize function is implemented using map:put, which ensures that the map entries holding function items (area, perimeter, and resize, are automatically present and unchanged in the modified map.
This kind of chaining extends to the case where a method returns zero or more maps. For example, suppose that rectangles are nested, and that $rectangle =?> contents() delivers a sequence of zero or more rectangles. Then the expression $rectangle =?> area() - sum($rectangle =?> contents() =?> area()) returns the difference between the area of the containing rectangle and the total area of the contained rectangles. This works because the dynamic function call $rectangle =?> contents() =?> area() applies the area function in each of the maps in the sequence returned by the expression $rectangle =?> contents().
A record type representing a rectangle containing nested rectangles might be defined in XQuery 4.0 like this:
declare record my:rectangle (
height as xs:double,
width as xs:double,
children as my:rectangle*
:= (),
area as fn(my:rectangle) as xs:double
:= fn{?height × ?width},
resize as fn(my:rectangle, xs:double) as my:rectangle
:= fn($rect, $factor) {
$rect => map:put('height', $rect?height × $factor)
=> map:put('width', $rect?width × $factor)
=> map:put('children', $rect?children =?> resize($factor))
},
contents as fn(my:rectangle) as my:rectangle*
:= fn{?children}
);The syntax on the right-hand side of an arrow operator has been relaxed; a dynamic function call no longer needs to start with a variable reference or a parenthesized expression, it can also be (for example) an inline function expression or a map or array constructor. [Issues 1716 1829 PRs 1763 1830 25 February 2025]
Arrow expressions apply a function (or more generally, a sequence of functions) to a value, using the value of the left-hand expression as the first argument to the function.
ArrowExpr | ::= | UnaryExpr (SequenceArrowTarget | MappingArrowTarget)* |
UnaryExpr | ::= | ("-" | "+")* ValueExpr |
SequenceArrowTarget | ::= | "=>" ArrowTarget |
ArrowTarget | ::= | FunctionCall | RestrictedDynamicCall |
FunctionCall | ::= | EQNameArgumentList |
| /* xgc: reserved-function-names */ | ||
| /* gn: parens */ | ||
RestrictedDynamicCall | ::= | (VarRef | ParenthesizedExpr | FunctionItemExpr | MapConstructor | ArrayConstructor) PositionalArgumentList |
VarRef | ::= | "$" EQName |
ParenthesizedExpr | ::= | "(" Expr? ")" |
FunctionItemExpr | ::= | NamedFunctionRef | InlineFunctionExpr |
NamedFunctionRef | ::= | EQName "#" IntegerLiteral |
| /* xgc: reserved-function-names */ | ||
InlineFunctionExpr | ::= | Annotation* ("function" | "fn") FunctionSignature? FunctionBody |
MapConstructor | ::= | "map"? "{" (MapConstructorEntry ** ",") "}" |
ArrayConstructor | ::= | SquareArrayConstructor | CurlyArrayConstructor |
PositionalArgumentList | ::= | "(" PositionalArguments? ")" |
PositionalArguments | ::= | (Argument ++ ",") |
MappingArrowTarget | ::= | "=!>" ArrowTarget |
The arrow syntax is particularly helpful when applying multiple functions to a value in turn. For example, the following expression invites syntax errors due to misplaced parentheses:
tokenize((normalize-unicode(upper-case($string))),"\s+")
In the following reformulation, it is easier to see that the parentheses are balanced:
$string => upper-case() => normalize-unicode() => tokenize("\s+")When the operator is written as =!>, the function is applied to each item in the sequence in turn. Assuming that $string is a single string, the above example could equally be written:
$string =!> upper-case() =!> normalize-unicode() =!> tokenize("\s+")The difference between the two operators is seen when the left-hand operand evaluates to a sequence:
(1, 2, 3) => avg()
returns a value of only one item, 2, the average of all three items.
This example could also be written as using the pipeline operator as:
(1, 2, 3) -> avg(.)
By contrast, an expression using the mapping arrow operator:
(1, 2, 3) =!> avg()
would return the original sequence of three items, (1, 2, 3), each item being the average of itself.
There are two significant differences between the pipeline operator-> and the sequence arrow operator=>:
The -> operator takes an arbitrary expression as its right-hand operand, whereas the => operator only acceptsrequires the right-hand operand to be a function call.
When the right hand operand is a function call, the first argument is omitted in the case of the => operator, but is included explicitly (as a context value expression, .) in the case of the -> operator.
The following example:
"The cat sat on the mat"
=> tokenize()
=!> concat(".")
=!> upper-case()
=> string-join(" ")returns "THE. CAT. SAT. ON. THE. MAT.". The first arrow could be written either as => or =!> because the operand is a singleton; the next two arrows have to be =!> because the function is applied to each item in the tokenized sequence individually; the final arrow must be => because the string-join function applies to the sequence as a whole.
Note:
It may be useful to think of this as a map/reduce pipeline. The functions introduced by =!> are mapping operations; the function introduced by => is a reduce operation.
The following example introduces an inline function to the pipeline:
(1 to 5) =!> xs:double() =!> math:sqrt() =!> fn($a) { $a + 1 }() => sum()This is equivalent to sum((1 to 5) ! (math:sqrt(xs:double(.)) + 1)).
The same effect can be achieved using a focus function:
(1 to 5) =!> xs:double() =!> math:sqrt() =!> fn { . + 1 }() => sum()It could also be expressed using the mapping operator !:
(1 to 5) ! xs:double(.) ! math:sqrt(.) ! (. + 1) => sum()
Note:
The ArgumentList may include PlaceHolders, though this is not especially useful. For example, the expression "$" => concat(?) is equivalent to concat("$", ?): its value is a function that prepends a supplied string with a $ symbol.
Note:
The ArgumentList may include keyword arguments if the function is identified statically (that is, by name). For example, the following is valid: $xml => xml-to-json(indent := true()) => parse-json(escape := false()).
The sequence arrow operator thus applies the supplied function to the left-hand operand as a whole, while the mapping arrow operator applies the function to each item in the value of the left-hand operand individually. In the case where the result of the left-hand operand is a single item, the two operators have the same effect.
Note:
The mapping arrow symbol =!> is intended to suggest a combination of function application (=>) and sequence mapping (!) combined in a single operation.
Similarly, the method call operator =?> is intended to suggest a combination of function application (=>) and map lookup (?) in a single operation.
The construct on the right-hand side of the arrow operator (=>) can either be a static function call, or a restricted form of dynamic function call. The restrictions are there to ensure that the two forms can be distinguished by the parser with limited lookahead. For a dynamic call, the function item(s) to be called can be expressed as a variable reference, an inline function expression, a named function reference, a map constructor, or an array constructor. Any other expression used to return the required function item must be enclosed in parentheses.
Because the semantics of the arrow operator (=>) are defined in terms of static and dynamic functions calls, it is possible for the right-hand side to deliver a sequence of functions; the result of the arrow expression is the sequence-concatenation of the results of the function calls. For example,
"London" => (upper-case#1, lower-case#1, string-length#1)returns the sequence ("LONDON", "london", 6).