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 G Changes since version 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).


14 Parsing and serializing

These functions convert between the lexical representation and XPath and XQuery data model representation of various file formats.

14.3 Functions on JSON Data

The functions listed in this section parse or serialize JSON data.

JSON is a popular format for exchange of structured data on the web: it is specified in [RFC 7159]. This section describes facilities allowing JSON data to be converted to and from XDM values.

This specification describes two ways of representing JSON data losslessly using XDM constructs. The first method uses XDM maps to represent JSON objects, and XDM arrays to represent JSON arrays. The second method represents all JSON constructs using XDM element and attribute nodes.

FunctionMeaning
fn:parse-jsonParses a string supplied in the form of a JSON text, returning the results typically in the form of a map or array.
fn:json-docReads an external resource containing JSON, and returns the result of parsing the resource as JSON.
fn:json-to-xmlParses a string supplied in the form of a JSON text, returning the results in the form of an XML document node.
fn:xml-to-jsonConverts an XML tree, whose format corresponds to the XML representation of JSON defined in this specification, into a string conforming to the JSON grammar.
fn:pinAdapts a map or array so that retrieval operations retain additional information.
fn:labelReturns the label associated with a labeled item, as a map.

Note also:

  • The function fn:serialize has an option to generate JSON output from a structure of maps and arrays.

  • The function fn:elements-to-maps enables arbitrary XML node trees to be converted to trees of maps and arrays suitable for serializing as JSON.

14.3.4 fn:parse-json

Changes in 4.0  

  1. The rules regarding use of non-XML characters in JSON texts have been relaxed.  [Issue 414 PR 546 25 July 2023]

  2. An option is provided to control how the JSON null value should be handled.  [Issue 960 PR 1028 20 February 2024]

  3. An option is provided to control how JSON numbers should be formatted.  [Issues 973 1037 PRs 975 1058 1246 12 March 2024]

  4. The default for the escape option has been changed to false. The 3.1 specification gave the default value as true, but this appears to have been an error, since it was inconsistent with examples given in the specification and with tests in the test suite.  [Issue 1555  11 November 2024]

  5. The order of entries in maps is retained.  [Issue 1651 PR 1703 14 January 2025]

Summary

Parses a string supplied in the form of a JSON text, returning the results typically in the form of a map or array.

Signature
fn:parse-json(
$valueas xs:string?,
$optionsas map(*)?:= {}
) as item()?
Properties

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

Rules

If the second argument is omitted or an empty sequence, the result is the same as calling the two-argument form with an empty map as the value of the $options argument.

The first argument is a JSON text as defined in [RFC 7159], in the form of a string. The function parses this string to return an XDM value.

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

Note:

The result will also be an empty sequence if $value is the string "null".

The $options argument can be used to control the way in which the parsing takes place. The option parameter conventions apply.

The entries that may appear in the $options map are as follows:

record(
liberal?as xs:boolean,
duplicates?as xs:string,
escape?as xs:boolean,
fallback?as (fn(xs:string) as xs:anyAtomicType)?,
null?as item()*,
number-parser?as (fn(xs:untypedAtomic) as item()?)?
)
KeyValueMeaning

liberal?

Determines whether deviations from the syntax of RFC7159 are permitted.
  • Type: xs:boolean

  • Default: false

false The input must consist of an optional byte order mark (which is ignored) followed by a string that conforms to the grammar of JSON-text in [RFC 7159]. An error must be raised [err:FOJS0001] if the input does not conform to the grammar.
true The input may contain deviations from the grammar of [RFC 7159], which are handled in an implementation-defined way. (Note: some popular extensions include allowing quotes on keys to be omitted, allowing a comma to appear after the last item in an array, allowing leading zeroes in numbers, and allowing control characters such as tab and newline to be present in unescaped form.) Since the extensions accepted are implementation-defined, an error may be raised [err:FOJS0001] if the input does not conform to the grammar.

duplicates?

Determines the policy for handling duplicate keys in a JSON object. To determine whether keys are duplicates, they are compared using the Unicode codepoint collation, after expanding escape sequences, unless the escape option is set to true, in which case keys are compared in escaped form.
  • Type: xs:string

  • Default: use-first

reject An error is raised [err:FOJS0003] if duplicate keys are encountered.
use-first If duplicate keys are present in a JSON object, all but the first of a set of duplicates are ignored.
use-last If duplicate keys are present in a JSON object, all but the last of a set of duplicates are ignored.

escape?

Determines whether special characters are represented in the XDM output in backslash-escaped form.
  • Type: xs:boolean

  • Default: false

false Any permitted character in the input, whether or not it is represented in the input by means of an escape sequence, is represented as an unescaped character in the result. Any other character or codepoint (for example, an unpaired surrogate) is passed to the fallback function as described below; in the absence of a fallback function, it is replaced by U+FFFD (REPLACEMENT CHARACTER, ) .
true JSON escape sequences are used in the result to represent special characters in the JSON input, as defined below, whether or not they were represented using JSON escape sequences in the input. The characters that are considered “special” for this purpose are:
  • all codepoints in the range U+0000 (NULL) to U+001F (IS1) or U+007F (DELETE) to U+009F (APC) ;

  • all codepoints that do not represent permitted characters, including codepoints representing unpaired surrogates;

  • the character U+005C (REVERSE SOLIDUS, BACKSLASH, \) itself.

Such characters are represented using a two-character escape sequence where available (for example, \t), or a six-character escape sequence otherwise (for example \uDEAD). Characters other than these are not escaped in the result, even if they were escaped in the input.

fallback?

Provides a function which is called when the input contains an escape sequence that represents a character that is not a permitted character. It is an error to supply the fallback option if the escape option is present with the value true.
  • Type: (fn(xs:string) as xs:anyAtomicType)?

  • Default: fn { char(0xFFFD) }

User-supplied function The function is called when the JSON input contains character that is not a permitted character It is called once for any surrogate that is not properly paired with another surrogate. The untyped atomic item supplied as the argument will always be a two- or six-character escape sequence, starting with a backslash, that conforms to the rules in the JSON grammar (as extended by the implementation if liberal:true() is specified): for example \b or \uFFFF or \uDEAD.

By default, the escape sequence is replaced with the Unicode REPLACEMENT CHARACTER. The function is not called for an escape sequence that is invalid against the grammar (for example \x0A). The string, which results from invoking fn:string on the result of the function, is inserted into the result in place of the invalid character. The function also has the option of raising a dynamic error by calling fn:error.

null?

Determines how the JSON null value should be represented.
  • Type: item()*

  • Default: ()

Value The supplied XDM value is used to represent the JSON null value. The default representation of null is an empty sequence, which works well in cases where setting a property of an object to null has the same meaning as omitting the property. It works less well in cases where null is used with some other meaning, because expressions such as the lookup operators ? and ?? flatten the result to a single sequence of items, which means that any entries whose value is an empty sequence effectively disappear. The property can be set to any XDM value; a suggested value is the xs:QName value fn:QName("http://www.w3.org/2005/xpath-functions", "null"), which is recognized by the JSON serialization method as representing the JSON value null.

number-parser?

Determines how numeric values should be processed.
  • Type: (fn(xs:untypedAtomic) as item()?)?

  • Default: xs:double#1

User-supplied function The supplied function is called to process the string value of any JSON number in the input. By default, numbers are processed by converting to xs:double using the XPath casting rules. Supplying the value xs:decimal#1 will instead convert to xs:decimal (which potentially retains more precision, but disallows exponential notation), while supplying a function that casts to (xs:decimal | xs:double) will treat the value as xs:decimal if there is no exponent, or as xs:double otherwise. Supplying the value fn:identity#1 causes the value to be retained unchanged as an xs:untypedAtomic. If the liberal option is false (the default), then the supplied number-parser is called if and only if the value conforms to the JSON grammar for numbers (for example, a leading plus sign and redundant leading zeroes are not allowed). If the liberal option is true then it is also called if the value conforms to an implementation-defined extension of this grammar.

The various structures that can occur in JSON are transformed recursively to XDM values as follows:

  1. A JSON object is converted to a map. The entries in the map correspond to the key/value pairs in the JSON object. The key is always of type xs:string; the associated value may be of any type, and is the result of converting the JSON value by recursive application of these rules. For example, the JSON text { "x": 2, "y": 5 } is transformed to the value { "x": 2, "y": 5 }.

    If duplicate keys are encountered in a JSON object, they are handled as determined by the duplicates option defined above.

    The order of entries is retained.

  2. A JSON array is transformed to an array whose members are the result of converting the corresponding member of the array by recursive application of these rules. For example, the JSON text [ "a", "b", null ] is transformed (by default) to the value [ "a", "b", () ].

  3. A JSON string is converted to an xs:string value. The handling of special characters depends on the escape and fallback options, as described in the table above.

  4. A JSON number is processed using the function supplied in the number-parser option; by default it is converted to an xs:double value using the rules for casting from xs:string to xs:double.

  5. The JSON boolean values true and false are converted to the corresponding xs:boolean values.

  6. The JSON value null is converted to the value given by the null option, which defaults to an empty sequence.

Error Conditions

A dynamic error [err:FOJS0001] occurs if the value of $value does not conform to the JSON grammar, unless the option "liberal":true() is present and the processor chooses to accept the deviation.

A dynamic error [err:FOJS0003] occurs if the option "duplicates": "reject" is present and the value of $value contains a JSON object with duplicate keys.

A dynamic error [err:FOJS0005] occurs if the $options map contains an entry whose key is defined in this specification and whose value is not valid for that key, or if it contains an entry with the key fallback when the option "escape":true() is also present.

Notes

The result of the function will be an instance of one of the following types. An instance of test (or in XQuery, typeswitch) can be used to distinguish them:

  • map(xs:string, item()?) for a JSON object

  • array(item()?) for a JSON array

  • xs:string for a JSON string

  • xs:double for a JSON number

  • xs:boolean for a JSON boolean

  • empty-sequence() for a JSON null (or for empty input)

If the input starts with a byte order mark, this function ignores it. The byte order mark may have been added to the data stream in order to facilitate decoding of an octet stream to a character string, but since this function takes a character string as input, the byte order mark serves no useful purpose.

The possibility of the input containing characters that are not valid in XML (for example, unpaired surrogates) arises only when such characters are expressed using JSON escape sequences. This is the only possibility, because the input to the function is an instance of xs:string, which by definition can contain only those characters that are valid in XML.

The serializer provides an option to ouput data in json-lines format. This is essentially a file containing one JSON text on each line. There is no corresponding option to parse json-lines input, but this can be achieved using the expression unparsed-text-lines($uri) => parse-json().

Examples
Expression:

parse-json('{ "x": 1, "y": [ 3, 4, 5 ] }')

Result:
{ "x": 1e0, "y": [ 3e0, 4e0, 5e0 ] }
Expression:

parse-json('"abcd"')

Result:
"abcd"
Expression:

parse-json('{ "x": "\\", "y": "\u0025" }')

Result:
{ "x": "\", "y": "%" }
Expression:
parse-json(
  '{ "x": "\\", "y": "\u0025" }',
  { 'escape': true() }
)
Result:
{ "x": "\\", "y": "%" }
Expression:
parse-json(
  '{ "x": "\\", "y": "\u0000" }'
)
Result:
{ "x": "\", "y": char(0xFFFD) }
Expression:
parse-json(
  '{ "x": "\\", "y": "\u0000" }',
  { 'escape': true() }
)
Result:
{ "x": "\\", "y": "\u0000" }
Expression:
parse-json(
  '{ "x": "\\", "y": "\u0000" }',
  { 'fallback': fn($s) { '[' || $s || ']' } }
)
Result:
{ "x": "\", "y": "[\u0000]" }
Expression:
parse-json(
  "1984.2",
  { 'number-parser': fn { xs:integer(round(.)) } }
)
Result:
1984
Expression:
parse-json(
  '[ 1, -1, 2 ]',
  { 'number-parser': fn  { boolean(. >= 0) } }
)
Result:
[ true(), false(), true() ]
Expression:
parse-json('[ "a", null, "b" ]',
  { 'null': xs:QName("fn:null") }
)
Result:
[ "a", xs:QName("fn:null"), "b" ]