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

XPath and XQuery Functions and Operators 4.0

W3C Editor's Draft 23 February 2026

This version:
https://qt4cg.org/specifications/xpath-functions-40/
Latest version of XPath and XQuery Functions and Operators 4.0:
https://qt4cg.org/specifications/xpath-functions-40/
Most recent Recommendation of XPath and XQuery Functions and Operators:
https://www.w3.org/TR/2017/REC-xpath-functions-31-20170321/
Editor:
Michael Kay, Saxonica <http://www.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: Specification in XML format and XML function catalog.


Abstract

This document defines constructor functions, operators, and functions on the datatypes defined in [XML Schema Part 2: Datatypes Second Edition] and the datatypes defined in [XQuery and XPath Data Model (XDM) 3.1]. It also defines functions and operators on nodes and node sequences as defined in the [XQuery and XPath Data Model (XDM) 3.1]. These functions and operators are defined for use in [XML Path Language (XPath) 4.0] and [XQuery 4.0: An XML Query Language] and [XSL Transformations (XSLT) Version 4.0] and other related XML standards. The signatures and summaries of functions defined in this document are available at: http://www.w3.org/2005/xpath-functions/.

A summary of changes since version 3.1 is provided at H Changes since 3.1.

Status of this Document

This version of the specification is work in progress. It is produced by the QT4 Working Group, officially the W3C XSLT 4.0 Extensions Community Group. Individual functions specified in the document may be at different stages of review, reflected in their History notes. Comments are invited, in the form of GitHub issues at https://github.com/qt4cg/qtspecs.

Dedication

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


2 Processing nodes

2.2 Other functions on nodes

This section specifies further functions on nodes. Nodes are formally defined in Section 6 Nodes DM31.

FunctionMeaning
fn:nameReturns the name of a node, as an xs:string that is either the zero-length string, or has the lexical form of an xs:QName.
fn:local-nameReturns the local part of the name of $node as an xs:string that is either the zero-length string, or has the lexical form of an xs:NCName.
fn:namespace-uriReturns the namespace URI part of the name of $node, as an xs:anyURI value.
fn:langThis function tests whether the language of $node, or the context value if the second argument is omitted, as specified by xml:lang attributes is the same as, or is a sublanguage of, the language specified by $language.
fn:rootReturns the root of the tree to which $node belongs. The function can be applied both to XNodesDM and to JNodesDM.
fn:pathReturns a path expression that can be used to select the supplied node relative to the root of its containing document.
fn:has-childrenReturns true if the supplied GNode has one or more child nodes (of any kind).
fn:siblingsReturns the supplied GNode together with its siblings, in document order.

2.2.6 fn:path

Changes in 4.0  

  1. Options are added to customize the form of the output.  [Issues 332 1660 PRs 1620 1886 29 November 2024]

  2. The function is extended to handle JNodes.  [Issue 2100  5 August 2025]

Summary

Returns a path expression that can be used to select the supplied node relative to the root of its containing document.

Signature
fn:path(
$nodeas gnode()?:= .,
$optionsas map(*)?:= {}
) as xs:string?
Properties

The zero-argument form of this function is deterministic, context-dependent, and focus-dependent.

The one-argument form of this function is deterministic, context-independent, and focus-independent.

The two-argument form of this function is deterministic, context-independent, and focus-independent.

Rules

The behavior of the function if the $nodeargument is omitted is exactly the same as if the context value (.) had been passed as the argument.

If $node is the empty sequence, the function returns the empty sequence.

The $options argument, if present, defines additional parameters controlling how the output is formatted. The option parameter conventions apply. The options available are as follows:

record(
origin?as gnode()?,
lexical?as xs:boolean,
namespaces?as map((xs:NCName | enum('')), xs:anyURI)?,
indexes?as xs:boolean
)
KeyMeaning

origin?

A GNode, which must be an ancestor of $node. If present, the returned path will be a relative path that selects $node starting from the supplied origin node, rather than from the root of the containing tree.
  • Type: gnode()?

  • Default: ()

lexical?

If true, the names of element nodes in the path are represented by the result of a call on the name function applied to each element. The result in this case does not contain sufficient information to identify the namespace URI of the element.
  • Type: xs:boolean

  • Default: false()

namespaces?

A map from namespace prefixes to namespace URIs, such as might be returned by the function fn:in-scope-namespaces. If a prefix is available for a given URI, it is used in preference to using Q{uri}local notation.
  • Type: map((xs:NCName | enum('')), xs:anyURI)?

  • Default: ()

indexes?

If true, the returned path includes the index positions of nodes. If false, only the node names are included.
  • Type: xs:boolean

  • Default: true()

Let R be the GNode supplied in the origin option, or the root GNode of the tree containing $node otherwise.

If $node is a document node, or a JNode with no parent, the function returns the string "/".

Otherwise, the function returns a string that consists of a sequence of steps, one for each ancestor-or-self of $node that is not an ancestor-or-self of R.

If R is an XNode other than a document node and the origin option is absent or empty, then this string is preceded by a string notionally representing a call to the fn:root function, expressed as follows:

  • If the lexical option is present with the value true, then the string "fn:root()".

  • If the namespaces option is present and defines a mapping from a non empty prefix P to the namespace URI http://www.w3.org/2005/xpath-functions, then "P:root()"

  • If the namespaces option is present and defines a mapping from the empty string to the namespace URI http://www.w3.org/2005/xpath-functions, then "root()"

  • Otherwise, "Q{http://www.w3.org/2005/xpath-functions}root()".

Each step is the concatenation of:

  1. The character "/", which is omitted for the first step if the origin option is present;

  2. A string whose form depends on the kind of node selected by that step, as follows:

    1. For an element node, the concatenation of:

      1. A representation of the element name, chosen as follows:

        1. If the lexical option is present with the value true, then the result of applying the name function to the element node.

        2. Otherwise, if the namespaces option is present and the element is in a namespace U and the namespaces option includes a mapping from a prefix P to the namespace U, then the string P:L, where L is the local part of the element name. If there is more than one such prefix, then one of them is chosen arbitrarily.

        3. Otherwise, if the namespaces option is present and the element is in a namespace U and the namespaces option includes a mapping from the zero-length string to the namespace U, then the local part of the element name.

        4. Otherwise, if the namespaces option is present and the element is in no namespace and the namespaces option includes no mapping from the zero-length string to any namespace, then the local part of the element name.

        5. Otherwise, the string Q{U}L, where U is the namespace URI of the element name or the empty string if the element is in no namespace, and L is the local part of the element name.

      2. Unless the indexes option is present with the value false, a string in the form [position] where position is an integer representing the one-based position of the selected node among its like-named siblings.

    2. For an attribute node, the concatenation of:

      1. The character "@"

      2. If the lexical option is present with the value true, then the result of applying the name function to the attribute node.

      3. Otherwise, if the attribute node is in no namespace, the local part of the attribute name.

      4. Otherwise, if the namespaces option is present, and if it includes a mapping from a non-empty namespace prefix P to the namespace URI of the attribute, then a string in the form P:L, where L is the local part of the attribute name. If there is more than one such prefix, then one of them is chosen arbitrarily.

      5. Otherwise, the string Q{U}L, where U is the namespace URI of the attribute name, and L is the local part of the attribute name.

    3. For a text node: text()[position] where position is an integer representing the position of the selected node among its text node siblings.

      The suffix [position] is omitted if the indexes option is present with the value false.

    4. For a comment node: comment()[position] where position is an integer representing the position of the selected node among its comment node siblings.

      The suffix [position] is omitted if the indexes option is present with the value false.

    5. For a processing-instruction node: processing-instruction(local)[position] where local is the name of the processing instruction node and position is an integer representing the position of the selected node among its like-named processing-instruction node siblings.

      The suffix [position] is omitted if the indexes option is present with the value false.

    6. For a namespace node:

      1. If the namespace node has a name: namespace::prefix, where prefix is the local part of the name of the namespace node (which represents the namespace prefix).

      2. If the namespace node has no name (that is, if it represents the default namespace): namespace::*[Ulocal-name() = ""]

        Here Ulocal-name() represents a call on the function fn:local-name and is formatted using the same conventions as the call on fn:root described earlier.

    7. For a JNode where the ·content· property of the parent is an array, then as the string *[N] where N is the value of the ·selector· property.

    8. For any other JNode (including the case where the ·content· property of the parent is a map):

      1. If the value of the ·parent· property of the JNode is an array, Otherwise:

      2. If the value is an xs:string, xs:untypedAtomic, or xs:anyURI that is castable to xs:NCName, then the result of casting the value to xs:NCName.

      3. If the value is an xs:string, xs:untypedAtomic, or xs:anyURI that is not castable to xs:NCName, then then as the string get("S") where S is the string value.

      4. If the value is numeric, then as the string get(N) where N is the result of casting the numeric value to xs:string.

      5. If the value is an xs:QName, then as the string get(#Q{uri}local) where uri and local are the namespace URI and local name parts of the QName.

      6. If the value is an xs:boolean, then as the string get(true()) or get(false()).

      7. If the value is of any other type, then as the string get(xs:T("S")) where T is the local part of the most specific built-in atomic type of which the value is an instance, and S is the result of casting the value to xs:string.

      TODO: Better handling of the case where the parent is neither a map nor an array, for example where it is a sequence of several maps or several arrays. It's hard to provide a better path for these when there is no AxisStep for selecting within such values.

Error Conditions

The following errors may be raised when $node is omitted:

  • If the context value is absentDM, type error [err:XPDY0002]XP

  • If the context value is not an instance of the sequence type node()?, type error [err:XPTY0004]XP.

If the value of the origin option is a node that is not an ancestor of $node (or in the absence of $node, the context value), dynamic error [err:FOPA0001].

Notes

Using the namespaces option to shorten the generated path is often convenient, but the resulting path may be unusable if the input tree contains multiple bindings for the same prefix.

Similarly, using the lexical option is convenient if there is no need for precise namespace information: it is especially suitable when the containing node tree declares no namespaces.

If the supplied argument is a map or an array, it will automatically be coerced to a JNode. This however is not useful, because this will be a root JNode, yielding the path /.

Examples
Variables
let $e := document {            
  <p xmlns="http://example.com/one" xml:lang="de" author="Friedrich von Schiller">
Freude, schöner Götterfunken,<br/>
Tochter aus Elysium,<br/>
Wir betreten feuertrunken,<br/>
Himmlische, dein Heiligtum.
</p>}
let $emp := 
  <employee xml:id="ID21256">
     <empnr>E21256</empnr>
     <first>John</first>
     <last>Brown</last>
  </employee>
Expression:
path($e)
Result:
'/'
Expression:
path($e/*:p)
Result:
'/Q{http://example.com/one}p[1]'
Expression:
path($e/*:p, { 'namespaces': in-scope-namespaces($e/*) })
Result:
'/p[1]'
Expression:
path($e/*:p, { 'indexes': false() })
Result:
'/Q{http://example.com/one}p'
Expression:
path($e/*:p/@xml:lang)
Result:
'/Q{http://example.com/one}p[1]/@Q{http://www.w3.org/XML/1998/namespace}lang'
Expression:
path($e//@xml:lang, { 'namespaces': in-scope-namespaces($e/*) })
Result:
'/p[1]/@xml:lang'
Expression:
path($e/*:p/@author)
Result:
'/Q{http://example.com/one}p[1]/@author'
Expression:
path($e/*:p/*:br[2])
Result:
'/Q{http://example.com/one}p[1]/Q{http://example.com/one}br[2]'
Expression:
path($e/*:p/*:br[2], {
  'namespaces': { 'N': 'http://example.com/one' },
  'indexes': false() 
})
Result:
'/N:p/N:br'
Expression:
path($e//text()[starts-with(normalize-space(), 'Tochter')])
Result:
'/Q{http://example.com/one}p[1]/text()[2]'
Expression:
path($e/*:p/*:br[2], { 'lexical': true() })
Result:
'/p[1]/br[2]'
Expression:
path($e/*:p/*:br[2], { 'lexical': true(), 'origin': $e/*:p })
Result:
'br[2]'
Expression:
path($emp)
Result:
'Q{http://www.w3.org/2005/xpath-functions}root()'
Expression:
path($emp/@xml:id)
Result:
'Q{http://www.w3.org/2005/xpath-functions}root()/@Q{http://www.w3.org/XML/1998/namespace}id'
Expression:
path($emp/empnr)
Result:
'Q{http://www.w3.org/2005/xpath-functions}root()/Q{}empnr[1]'
Expression:
path($emp/empnr, { 'lexical': true() })
Result:
'fn:root()/empnr[1]'
Expression:
path($emp/empnr, {
  'namespaces': {
    'fn': 'http://www.w3.org/2005/xpath-functions',
    '': ''
  }
})
Result:
'fn:root()/empnr[1]'
Expression:
let $in := [{"b":[3,4]}]
return path($in/*[1]/b/*[2])
Result:
"/get(2)/b/get(2)
"/*[1]/b/*[2]
Expression:
let $in := [{"b":[3,4]}]
return path($in/*[1]/b/*[2])
let $in := [[{'a':1}], [{'a':2}]]
return path($in//a[. = 2])
Result:
"/get(2)/b/get(2)
"/*[2]/*[1]/a

2.2.7 fn:has-children

Changes in 4.0  

  1. Generalized to work with JNodes as well as XNodes.  [Issue 2100 ]

Summary

Returns true if the supplied GNode has one or more child nodes (of any kind).

Signature
fn:has-children(
$nodeas gnode()?:= .
) as xs:boolean
Properties

The zero-argument form of this function is deterministic, context-dependent, and focus-dependent.

The one-argument form of this function is deterministic, context-independent, and focus-independent.

Rules

If the argument is omitted, it defaults to the context value (.).

Provided that the supplied argument $node matches the expected type gnode()?, the result of the function call fn:has-children($node) is defined to be the same as the result of the expression fn:exists($node/child::gnode()).

Error Conditions

The following errors may be raised when $node is omitted:

  • If the context value is absentDM, type error [err:XPDY0002]XP

  • If the context value is not an instance of the sequence type gnode()?, type error [err:XPTY0004]XP.

Notes

If $node is an empty sequence the result is false.

The motivation for this function is to support streamed evaluation. According to the streaming rules in [XSL Transformations (XSLT) Version 4.0], the following construct is not streamable:

<xsl:if test="exists(row)">
  <ulist>
    <xsl:for-each select="row">
      <item><xsl:value-of select="."/></item>
    </xsl:for-each>
  </ulist>
</xsl:if>

This is because it makes two downward selections to read the child row elements. The use of fn:has-children in the xsl:if conditional is intended to circumvent this restriction.

Although the function was introduced to support streaming use cases, it has general utility as a convenience function.

If the supplied argument is a map or an array, it will automatically be coerced to a JNode.

Examples
Variables
let $e := <doc>
  <p id="alpha">One</p>
  <p/>
  <p>Three</p>
  <?pi 3.14159?>
</doc>
ExpressionResult
has-children($e)
true()
has-children($e//p[1])
true()
has-children($e//p[2])
false()
has-children($e//p[3])
true()
has-children($e//processing-instruction())
false()
has-children($e//p[1]/text())
false()
has-children($e//p[1]/@id)
false()
[1,2,3] => has-children()
true()
[] => has-children()
false()

2.3 Functions on sequences of nodes

This section specifies functions on sequences of nodes.

FunctionMeaning
fn:distinct-ordered-nodesRemoves duplicate GNodes and sorts the input into document order.
fn:innermostReturns every GNode within the input sequence that is not an ancestor of another member of the input sequence; the GNodes are returned in document order with duplicates eliminated.
fn:outermostReturns every GNode within the input sequence that has no ancestor that is itself a member of the input sequence; the nodes are returned in document order with duplicates eliminated.

2.3.2 fn:innermost

Changes in 4.0  

  1. Generalized to work with JNodes as well as XNodes.  [Issue 2100 ]

Summary

Returns every GNode within the input sequence that is not an ancestor of another member of the input sequence; the GNodes are returned in document order with duplicates eliminated.

Signature
fn:innermost(
$nodesas nodegnode()*
) as nodegnode()*
Properties

This function is deterministic, context-independent, and focus-independent.

Rules

The effect of the function call fn:innermost($nodes) is defined to be equivalent to the result of the expression:

$nodes except $nodes/ancestor::gnode()

That is, the function takes as input a sequence of GNodes, and returns every GNode within the sequence that is not an ancestor of another GNode within the sequence; the GNodes are returned in document order with duplicates eliminated.

Examples
Notes

If the source document contains nested sections represented by div elements, the expression innermost(//div) returns those div elements that do not contain further div elements.

If the supplied argument includes a map or an array, it will automatically be coerced to a JNode.

Examples
Expression:
parse-xml("<doc>
    <div id='a'><div id='b'><div id='c'/></div></div>
  </doc>")//div
   => innermost() => string(@id)
Result:
"c"
Expression:
[[[1,2], [3,4]], [[5,6], [7,8]]]")//array(*)
   => innermost()
Result:
[1,2], [3,4], [5,6], [7,8]

2.3.3 fn:outermost

Changes in 4.0  

  1. Generalized to work with JNodes as well as XNodes.  [Issue 2100 ]

Summary

Returns every GNode within the input sequence that has no ancestor that is itself a member of the input sequence; the nodes are returned in document order with duplicates eliminated.

Signature
fn:outermost(
$nodesas gnode()*
) as gnode()*
Properties

This function is deterministic, context-independent, and focus-independent.

Rules

The effect of the function call fn:outermost($nodes) is defined to be equivalent to the result of the expression:

$nodes[not(ancestor::gnode() intersect $nodes)]/.

That is, the function takes as input a sequence of GNodes, and returns every GNode within the sequence that does not have another GNode within the sequence as an ancestor; the GNodes are returned in document order with duplicates eliminated.

Notes

The formulation $nodes except $nodes/descendant::node() might appear to be simpler, but does not correctly account for attribute nodes, as these are not descendants of their parent element.

The motivation for the function was based on XSLT streaming use cases. There are cases where the [XSL Transformations (XSLT) Version 4.0] streaming rules allow the construct outermost(//section) but do not allow //section; the function can therefore be useful in cases where it is known that sections will not be nested, as well as cases where the application actually wishes to process all sections except those that are nested within another.

If the supplied argument includes a map or an array, it will automatically be coerced to a JNode.

Examples
Expression:

If the source document contains nested sections represented by div elements, the expression outermost(//div) returns those div elements that are not contained within further div elements.

parse-xml("<doc>
     <div id='a'><div id='b'><div id='c'/></div></div>
  </doc>")//div
   => outermost() => string(@id)
Result:
"a"
Expression:
[[[1], [2]], [[3], [4]], [[5], [6]]]")//array(*)
   => outermost() => array:size()
Result:
3