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


20 Processing JNodes

Changes in 4.0  

  1. Introduced the concept of JNodes.   [Issue 2025 PR 2031 11 June 2025]

A JNodeDM is a wrapper around a map or array, or around a value that appears within the content of a map or array. JNodes are described at Section 8.4 JNodesDM. Wrapping a map or array in a JNode enables the use of path expressions such as $jnode/descendant::title, as described at Section 4.6 Path ExpressionsXP.

In addition to the functions defined in this section, functions that operate on JNodes include:

fn:distinct-ordered-nodes
fn:generate-id
fn:root
fn:siblings
fn:transitive-closure

20.1 Functions on JNodes

20.1.1 fn:jnode

Changes in 4.0  

  1. New in 4.0  [Issue 2025 PR 2031 12 June 2025]

Summary

Delivers a root JNodeDM wrapping a map or array, enabling the use of lookup expression to navigate a JTreeDM rooted at that map or array.

Signature
fn:jnode(
$inputas (map(*)|array(*))
) as jnode-type(map(*)|array(*))
Properties

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

Rules

The function creates a JNodeDM that wraps the supplied map or array. Specifically, it creates a root JNode whose ·content· property is $input, and whose ·parent·, ·position·, and ·selector· properties are absent.

This has the effect that lookup expressions starting from this JNode retain information for subsequent navigation.

A JNode has unique identity. If two maps or arrays M1 and M2 have the same function identity, as determined by the function-identity function, then jnode(M1) is jnode-(M2)must return true: that is, the same JNode must be delivered for both.

Notes

It is to some extent implementation-defined whether two maps or arrays have the same function identity. Processors should ensure as a minimum that when a variable $m is bound to a map or array, calling jnode($m) more than once (with the same variable reference) will deliver the same JNode each time.

The effect of the coercion rules is technically that if an existing JNode is supplied as $input, the wrapped value will be extracted, and then rewrapped as a JNode: in practice, this can be short-circuited by returning the supplied JNode unchanged.

Although fn:jnode is available as a function for user applications to call explicitly, it is also invoked implicitly by some expressions, notably when a path expression is written in a form such as $map/child::*. Specifically, if the left-hand operand of the / operator is a map or array, then the supplied map or array is implicitly wrapped in a JNode.

The effect of applying fn:jnode to a map or array is that subsequent retrieval operations within the wrapped map or array return results that retain useful information about where the results were found. For example, consider an expression such as json-doc($source)//name. This expression returns a set of JNodes representing all entries in the JTree having the key "name"; each of these JNodes contains not only the value of the relevant "name" entry, but also the key (which in this simple example is always "name" and the containing map. This means, for example, if $result is the result of the expression json-doc($source) // name, then:

  • $result / .. / ssn locates the map that contained each name, and returns the value of the ssn entry in that map.

  • $result / ancestor::course returns any course entries in containing maps.

  • $result / ancestor::* => jnode-selector() returns a sequence of map keys and array index values representing the location of the found entries within the JSON structure.

An alternative way of wrapping a map or array, rather than calling jnode($X), is to use the path expression $X/..

Examples
Expression:

jnode([ "a", "b", "c" ])/*[1]/../*[last()] => string()

Result:
"c"

(The call on fn:jnode would happen automatically).

Expression:

jnode([ "a", "b", "c", "d" ])/* => jnode-selector()

Result:
1, 2, 3, 4
Expression:
let $data := {
  "fr": { "capital": "Paris", "languages": [ "French" ] }, 
  "de": { "capital": "Berlin", "languages": [ "German" ] }
}
return jnode($data)//languages[. = 'German']/../capital) => string()
Result:
"Berlin"