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

XQuery 4.0: An XML Query Language

W3C Editor's Draft 23 February 2026

This version:
https://qt4cg.org/specifications/xquery-40/
Most recent version of XQuery:
https://qt4cg.org/specifications/xquery-40/
Most recent Recommendation of XQuery:
https://www.w3.org/TR/2017/REC-xquery-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

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.

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).


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 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
| QuantifiedExpr
| SwitchExpr
| TypeswitchExpr
| IfExpr
| TryCatchExpr
| OrExpr
ExprSingle::=FLWORExpr
| QuantifiedExpr
| SwitchExpr
| TypeswitchExpr
| IfExpr
| TryCatchExpr
| OrExpr
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::=TryClauseCatchClause+
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.

4.5 Functions

Functions in XQuery 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::=Annotation* ("function" | "fn") FunctionSignature? FunctionBody
Annotation::="%" EQName ("(" (AnnotationValue ++ ",") ")")?
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.

An inline function expression may have annotations. The only annotation defined in XQuery 4.0 for inline function expressions is the annotation %method, described in 4.5.6.1 Methods. It is a static error [err:XQST0125] if an inline function expression is annotated as %public or %private. An implementation can define annotations, in its own namespace, to support functionality beyond the scope of this specification.

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 Annotations andSequenceTypes 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: The annotations explicitly included in the inline function expression. .

  • 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.14.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.24 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. In practice, this problem can be avoided by defining rectangle as a named record type (see 5.20 Named Record Types) and using its constructor function.

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.

Note:

Methods are often useful in conjunction with named record types: see 5.20.3 Using Methods in Records.

5 Modules and Prologs

Module::=VersionDecl? (LibraryModule | MainModule)
VersionDecl::="xquery" (("encoding" StringLiteral) | ("version" StringLiteral ("encoding" StringLiteral)?)) Separator
LibraryModule::=ModuleDeclProlog
ModuleDecl::="module" "namespace" NCName "=" URILiteralSeparator
Prolog::=((DefaultNamespaceDecl | Setter | NamespaceDecl | Import) Separator)* ((ContextValueDecl | VarDecl | FunctionDecl | ItemTypeDecl | NamedRecordTypeDecl | OptionDecl) Separator)*
DefaultNamespaceDecl::="declare" "fixed"? "default" ("element" | "function") "namespace" URILiteral
Setter::=BoundarySpaceDecl | DefaultCollationDecl | BaseURIDecl | ConstructionDecl | OrderingModeDecl | EmptyOrderDecl | CopyNamespacesDecl | DecimalFormatDecl
BoundarySpaceDecl::="declare" "boundary-space" ("preserve" | "strip")
DefaultCollationDecl::="declare" "default" "collation" URILiteral
BaseURIDecl::="declare" "base-uri" URILiteral
ConstructionDecl::="declare" "construction" ("strip" | "preserve")
OrderingModeDecl::="declare" "ordering" ("ordered" | "unordered")
EmptyOrderDecl::="declare" "default" "order" "empty" ("greatest" | "least")
CopyNamespacesDecl::="declare" "copy-namespaces" PreserveMode "," InheritMode
DecimalFormatDecl::="declare" (("decimal-format" EQName) | ("default" "decimal-format")) (DFPropertyName "=" StringLiteral)*
NamespaceDecl::="declare" "namespace" NCName "=" URILiteral
Import::=SchemaImport | ModuleImport
SchemaImport::="import" "schema" SchemaPrefix? URILiteral ("at" (URILiteral ++ ","))?
ModuleImport::="import" "module" ("namespace" NCName "=")? URILiteral ("at" (URILiteral ++ ","))?
Separator::=";"
ContextValueDecl::="declare" "context" (("value" ("as" SequenceType)?) | ("item" ("as" ItemType)?)) ((":=" VarValue) | ("external" (":=" VarDefaultValue)?))
VarDecl::="declare" Annotation* "variable" VarNameAndType ((":=" VarValue) | ("external" (":=" VarDefaultValue)?))
FunctionDecl::="declare" Annotation* "function" EQName "(" ParamListWithDefaults? ")" TypeDeclaration? (FunctionBody | "external")
/* xgc: reserved-function-names */
ItemTypeDecl::="declare" Annotation* "type" EQName "as" ItemType
NamedRecordTypeDecl::="declare" Annotation* "record" EQName "(" (ExtendedFieldDeclaration ** ",") ExtensibleFlag? ")"
OptionDecl::="declare" "option" EQNameStringLiteral
MainModule::=PrologQueryBody
QueryBody::=Expr
Expr::=(ExprSingle ++ ",")

A query can be assembled from one or more fragments called modules. [Definition: A module is a fragment of XQuery code that conforms to the Module grammar and can independently undergo the static analysis phase described in 2.3.3 Expression Processing. Each module is either a main module or a library module.]

[Definition: A main module consists of a Prolog followed by a Query Body.] A query has exactly one main module. In a main module, the Query Body is evaluated with respect to the static and dynamic contexts of the main module in which it is found, and its value is the result of the query.

[Definition: A module that does not contain a Query Body is called a library module. A library module consists of a module declaration followed by a Prolog.] A library module cannot be evaluated directly; instead, it provides function and variable declarations that can be imported into other modules.

The XQuery syntax does not allow a module to contain both a module declaration and a Query Body.

[Definition: A Prolog is a series of declarations and imports that define the processing environment for the module that contains the Prolog.] Each declaration or import is followed by a semicolon. A Prolog is organized into two parts.

The first part of the Prolog consists of setters, imports, namespace declarations, and default namespace declarations. [Definition: Setters are declarations that set the value of some property that affects query processing, such as construction mode or default collation.] Namespace declarations and default namespace declarations affect the interpretation of lexical QNames within the query. Imports are used to import definitions from schemas and modules. [Definition: The target namespace of a module is the namespace of the objects (such as elements or functions) that it defines. ]

The second part of the Prolog consists of declarations of variables, functions, and options. These declarations appear at the end of the Prolog because they may be affected by declarations and imports in the first part of the Prolog.

[Definition: The Query Body, if present, consists of an expression that defines the result of the query.] Evaluation of expressions is described in 4 Expressions. A module can be evaluated only if it has a Query Body.

5.20 Named Record Types

Although item type declarations, as described in 5.19 Item Type Declarations, can be used to give names to record types as well as any other item type, named record types as described in this section provide a more concise syntax, plus additional functionality. In particular:

  • Named record types can be recursive.

  • Named record types implicitly create a constructor function that can be used to create instances of the record type.

  • A field in a named record type can be a function that has implicit access to the record on which it is defined, rather like methods in object-oriented languages.

The syntax is as follows:

NamedRecordTypeDecl::="declare" Annotation* "record" EQName "(" (ExtendedFieldDeclaration ** ",") ExtensibleFlag? ")"
Annotation::="%" EQName ("(" (AnnotationValue ++ ",") ")")?
EQName::=QName | URIQualifiedName
ExtendedFieldDeclaration::=FieldDeclaration (":=" ExprSingle)?
FieldDeclaration::=FieldName "?"? ("as" SequenceType)?
FieldName::=NCName | StringLiteral
StringLiteral::=AposStringLiteral | QuotStringLiteral
/* ws: explicit */
SequenceType::=("empty-sequence" "(" ")")
| (ItemTypeOccurrenceIndicator?)
ExprSingle::=FLWORExpr
| QuantifiedExpr
| SwitchExpr
| TypeswitchExpr
| IfExpr
| TryCatchExpr
| OrExpr
ExtensibleFlag::="," "*"

A named record declaration serves as both a named item type and as a function definition, and it therefore inherits rules from both these roles. In particular:

  1. Its name must not be the same as the name of any other named item type, or any generalized atomic type, that is present in the same static context [err:XQST0048].

  2. If the declaration appears within a library module then its name must be in the target namespace of the library module [err:XQST0048].

  3. As a function, it must not have an arity range that overlaps the arity range of any other function declaration having the same name in the same static context.

  4. The order of field declarations is significant, because it determines the order of arguments in a call to the constructor function.

  5. The fields must have distinct names. [err:XPST0021]

  6. In order to work as both a record type and a function declaration, the names of the fields must be simple NCNames in no namespace; the names must not be written as string literals [err:XPST0003].

    Note:

    This is described here as a semantic constraint, but an implementation might choose to impose it at the level of the grammar.

  7. If an initializing expression is present in an ExtendedFieldDeclaration, it must follow the rules for the initializing expression of a parameter in a function declaration, given in 5.18.3 Function Parameters. In particular, if any field has an initializing expression then all following fields must have an initializing expression.

  8. Any annotations that are present, such as %public or %private, apply both to the item type declaration and to the function declaration.

5.20.3 Using Methods in Records

Named record declarations are useful in conjunction with methods, described in 4.5.6.1 Methods. For example, given the declaration:

declare record geom:rectangle(
  width     as xs:double,
  height    as xs:double,
  area      as fn() as xs:double := 
               %method fn() { 
                  $this?width × $this?height 
               },
  perimeter as fn() as xs:double := 
               %method fn() {
                  2 * ($this?width + $this?height)
               },
  expand    as fn($factor as xs:double) as geom:rectangle := 
               %method fn() {
                  geom:rectangle($this?width * $factor, $this?height * $factor)
               }   
);
declare record geom:rectangle(
  width     as xs:double,
  height    as xs:double,
  area      as fn() as xs:double := 
               %method fn() { 
                  $this?width × $this?height 
               },
  perimeter as fn() as xs:double := 
               %method fn() {
                  2 × ($this?width + $this?height)
               },
  expand    as fn($factor as xs:double) as geom:rectangle := 
               %method fn() {
                  geom:rectangle($this?width × $factor, $this?height × $factor)
               }   
);

The following expression constructs a rectangle and calculates its area:

let $box := geom:rectangle(3, 2)
return $box?area()

The following expands the dimensions of the rectangle and calculates the perimeter of the result:

let $box := geom:rectangle(3, 2)
return $box?expand(2)?perimeter()

Note:

There is nothing to stop a user constructing an instance of geom:rectangle in which the area field holds some different function: while the syntax imitates that of object-oriented languages, there is no encapsulation.