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


12 Processing binary values

12.1 Comparisons of base64Binary and hexBinary values

The following comparison operators on xs:hexBinary and xs:base64Binary values are defined. Each returns a boolean value.

These functions can be used to compare any xs:hexBinary or xs:base64Binary value with any other xs:hexBinary or xs:base64Binary value: both types have the same value space, namely a sequence of octets which are treated as integers in the range 0 to 255.

FunctionMeaning
op:binary-equalReturns true if both binary values contain the same octet sequence.
op:binary-less-thanReturns true if the first argument is less than the second.

12.1.1 op:binary-equal

Changes in 4.0  

  1. Atomic items of types xs:hexBinary and xs:base64Binary are now mutually comparable.  [Issues 911 2139 PR 980 30 January 2024]

Summary

Returns true if both binary values contain the same octet sequence.

Operator Mapping

Defines the semantics of the eq and ne operators when applied to two xs:hexBinary or xs:base64Binary values.

Signature
op:binary-equal(
$value1as (xs:hexBinary | xs:base64Binary),
$value2as (xs:hexBinary | xs:base64Binary)
) as xs:boolean
Rules

The function returns true if $value1 and $value2 are of the same length, measured in binary octets, and contain the same octets in the same order. Otherwise, it returns false.

12.1.2 op:binary-less-than

Changes in 4.0  

  1. Atomic items of types xs:hexBinary and xs:base64Binary are now mutually comparable.  [Issues 911 2139 PR 980 30 January 2024]

Summary

Returns true if the first argument is less than the second.

Operator Mapping

Defines the semantics of the lt operator when applied to two xs:hexBinary or xs:base64Binaryvalues. Also used in the definition of the ge operator.

Signature
op:binary-less-than(
$arg1as (xs:hexBinary | xs:base64Binary),
$arg2as (xs:hexBinary | xs:base64Binary)
) as xs:boolean
Rules

Each of the two arguments are converted to a sequence of octets, $A and $B, and the first octet in each sequence, $a and $b, are compared.

  1. If $a is empty and $b is non-empty return true.

  2. If $b is empty return false.

  3. Otherwise (neither $a nor $b are empty):

    1. If $a and $b are identical the result is obtained by applying these same rules recursively to fn:tail($A) and fn:tail($B).

    2. Otherwise, if $a is less than $b, treating the value of each octet as an unsigned integer in the range 0 to 255, then return true, otherwise return false.

14 Processing sequences

A sequence is an ordered collection of zero or more items. An item is a node, an atomic item, or a function, such as a map or an array. The terms sequence and item are defined formally in [XQuery 4.0: An XML Query Language] and [XML Path Language (XPath) 4.0].

14.2 Comparison functions

The functions in this section perform comparisons between the items in one or more sequences.

FunctionMeaning
fn:atomic-equalDetermines whether two atomic items are equal, under the rules used for comparing keys in a map.
fn:deep-equal This function assesses whether two sequences are deep-equal to each other. To be deep-equal, they must contain items that are pairwise deep-equal; and for two items to be deep-equal, they must either be atomic items that compare equal, or nodes of the same kind, with the same name, whose children are deep-equal, or maps with matching entries, or arrays with matching members.
fn:compareReturns -1, 0, or 1, depending on whether the first value is less than, equal to, or greater than the second value.
fn:distinct-valuesReturns the values that appear in a sequence, with duplicates eliminated.
fn:duplicate-valuesReturns the values that appear in a sequence more than once.
fn:index-ofReturns a sequence of positive integers giving the positions within the sequence $input of items that are equal to $target.
fn:starts-with-subsequenceDetermines whether one sequence starts with another, using a supplied callback function to compare items.
fn:ends-with-subsequenceDetermines whether one sequence ends with another, using a supplied callback function to compare items.
fn:contains-subsequenceDetermines whether one sequence contains another as a contiguous subsequence, using a supplied callback function to compare items.

14.2.1 fn:atomic-equal

Changes in 4.0  

  1. New in 4.0. The function is identical toreplaces the internal op:same-key function in 3.1

  2. Atomic items of types xs:hexBinary and xs:base64Binary are now mutually comparable. In rare cases, where an application uses both types and assumes they are distinct, this can represent a backwards incompatibility.  [Issue 2139  14 August 2025]

Summary

Determines whether two atomic items are equal, under the rules used for comparing keys in a map.

Signature
fn:atomic-equal(
$value1as xs:anyAtomicType,
$value2as xs:anyAtomicType
) as xs:boolean
Properties

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

Rules

The function fn:atomic-equal is used to compare two atomic items for equality. This function has the following properties (which do not all apply to the eq operator):

  • Any two atomic items can be compared, regardless of their type.

  • No dynamic error is ever raised (the result is either true or false).

  • The result of the comparison never depends on the static or dynamic context.

  • Every value (including NaN) is equal to itself.

  • The comparison is symmetric: if A equals B, then B equals A.

  • The comparison is transitive: if A equals B and B equals C, then A equals C.

The function returns true if and only if one of the following conditions is true:

  1. All of the following conditions are true:

    1. $value1 is an instance of xs:string, xs:anyURI, or xs:untypedAtomic

    2. $value2 is an instance of xs:string, xs:anyURI, or xs:untypedAtomic

    3. fn:codepoint-equal($value1, $value2)

    Note:

    Strings are compared without any dependency on collations.

  2. All of the following conditions are true:

    1. $value1 is an instance of xs:decimal, xs:double, or xs:float

    2. $value2 is an instance of xs:decimal, xs:double, or xs:float

    3. One of the following conditions is true:

      1. Both $value1 and $value2 are NaN

        Note:

        xs:double('NaN') is the same key as xs:float('NaN')

      2. Both $value1 and $value2 are positive infinity

        Note:

        xs:double('INF') is the same key as xs:float('INF')

      3. Both $value1 and $value2 are negative infinity

        Note:

        xs:double('-INF') is the same key as xs:float('-INF')

      4. $value1 and $value2 when converted to decimal numbers with no rounding or loss of precision are mathematically equal.

        Note:

        Every instance of xs:double, xs:float, and xs:decimal can be represented exactly as a decimal number provided enough digits are available both before and after the decimal point. Unlike the eq relation, which converts both operands to xs:double values, possibly losing precision in the process, this comparison is transitive.

        Note:

        Positive and negative zero compare equal.

  3. All of the following conditions are true:

    1. One of the following conditions is true:

      1. $value1 and $value2 are both instances of xs:date.

      2. $value1 and $value2 are both instances of xs:time.

      3. $value1 and $value2 are both instances of xs:dateTime.

      4. $value1 and $value2 are both instances of xs:gYear.

      5. $value1 and $value2 are both instances of xs:gYearMonth.

      6. $value1 and $value2 are both instances of xs:gMonth.

      7. $value1 and $value2 are both instances of xs:gMonthDay.

      8. $value1 and $value2 are both instances of xs:gDay.

    2. One of the following conditions is true:

      1. Both $value1 and $value2 have a timezone

      2. Neither $value1 nor $value2 has a timezone

    3. $value1 eq $value2

    Note:

    Values having a timezone are never equal to values without one. The implicit timezone is not used.

  4. All of the following conditions are true:

    1. $value1 is an instance of xs:hexBinary or xs:base64Binary

    2. $value2 is an instance of xs:hexBinary or xs:base64Binary

    3. op:binary-equal($value1, $value2)

  5. All of the following conditions are true:

    1. One of the following conditions is true:

      1. $value1 and $value2 are both instances of xs:boolean.

      2. $value1 and $value2 are both instances of xs:QName.

      3. $value1 and $value2 are both instances of xs:NOTATION.

      4. $value1 and $value2 are both instances of xs:duration.

      5. $value1 and $value2 are both instances of xs:hexBinary.

      6. $value1 and $value2 are both instances of xs:base64Binary.

    2. $value1 eq $value2

Notes

The internal function op:same-key was introduced in an earlier version of this specification for comparing keys within a map. In this version of the specification, the functionality is unchanged, but the function is exposed so that it is available directly to applications.

The function is used to assess whether two atomic items are considered to be duplicates when used as keys in a map. A map cannot contain two separate entries whose keys are the same as defined by this function. The function is also used when matching keys in functions such as map:get and map:remove.

The rules for comparing keys in a map are chosen to ensure that the comparison is:

  • Context-free: there is no dependency on the static or dynamic context

  • Error-free: any two atomic items can be compared, and the result is either true or false, never an error

  • Transitive: if A is the same key as B, and B is the same key as C, then A is the same key as C.

Two atomic items may be distinguishable even though they are equal under this comparison. For example: they may have different type annotations; dates and times may have different timezones; xs:QName values may have different prefixes.

Unlike the eq operator and the fn:deep-equal function, xs:hexBinary and xs:base64Binary values are considered distinct. This decision was made in order to preserve backwards compatibility: if the values were treated as interchangeable, it would become impossible to construct certain maps that could be validly constructed using earlier versions of the specification, and it would be difficult to make maps fully interoperable between processors supporting different language versions, for example when calling fn:transform.

As always, any algorithm that delivers the right result is acceptable. For example, when testing whether an xs:double value D is the same key as an xs:decimal value that has N significant digits, it is not necessary to know all the digits in the decimal expansion of D to establish the result: computing the first N+1 significant digits (or indeed, simply knowing that there are more than N significant digits) is sufficient.

Examples
Expression:

atomic-equal(3, 3)

Result:
true()
Expression:

atomic-equal(3, 3e0)

Result:
true()
Expression:

atomic-equal(3.1, 3.1e0)

Result:
false()
Expression:

atomic-equal(xs:double('NaN'), xs:float('NaN'))

Result:
true()
Expression:

atomic-equal("a", "a")

Result:
true()
Expression:

atomic-equal("a", "A")

Result:
false()
Expression:

atomic-equal("a", xs:untypedAtomic("a"))

Result:
true()
Expression:
atomic-equal(
  "https://www.w3.org/",
  xs:anyURI("https://www.w3.org/")
)
Result:
true()
Expression:

atomic-equal(12, "12")

Result:
false()

14.2.2 fn:deep-equal

Changes in 4.0  

  1. When comments and processing instructions are ignored, any text nodes either side of the comment or processing instruction are now merged prior to comparison.  [Issue 930 PR 933 16 January 2024]

  2. The $options parameter has been added, absorbing the $collation parameter.  [Issues 934 1167 PR 1191 21 May 2024]

  3. A callback function can be supplied for comparing individual items.  [Issues 99 1142 PRs 1120 1150 9 April 2024]

  4. Atomic items of types xs:hexBinary and xs:base64Binary are now mutually comparable. In rare cases, where an application uses both types and assumes they are distinct, this can represent a backwards incompatibility.  [Issue 2139  14 August 2025]

Summary

This function assesses whether two sequences are deep-equal to each other. To be deep-equal, they must contain items that are pairwise deep-equal; and for two items to be deep-equal, they must either be atomic items that compare equal, or nodes of the same kind, with the same name, whose children are deep-equal, or maps with matching entries, or arrays with matching members.

Signature
fn:deep-equal(
$input1as item()*,
$input2as item()*,
$optionsas (xs:string | map(*))?:= {}
) as xs:boolean
Properties

The two-argument form of this function is deterministic, context-dependent, and focus-independent. It depends on collations, and implicit timezone.

The three-argument form of this function is deterministic, context-dependent, and focus-independent. It depends on collations, and static base URI, and implicit timezone.

Rules

The $options argument, if present, defines additional parameters controlling how the comparison is done. If it is supplied as a map, then the option parameter conventions apply.

For backwards compatibility reasons, the $options argument can also be set to a string containing a collation name. Supplying a string $S for this argument is equivalent to supplying the map { 'collation': $S }. Omitting the argument, or supplying the empty sequence, is equivalent to supplying an empty map.

If the two sequences ($input1 and $input2) are both empty, the function returns true.

If the two sequences are of different lengths, the function returns false.

If the two sequences are of the same length, the comparison is controlled by the ordered option:

  • By default, the option is true: The function returns true if and only if every item in the sequence $input1 is deep-equal to the item at the same position in the sequence $input2.

  • If the option is set to false, the function returns false if and only if every item in the sequence $input1 is deep-equal to an item at some position in the sequence $input2, and vice versa.

The rules for deciding whether two items are deep-equal appear below.

The entries that may appear in the $options map are as follows. The detailed rules for the interpretation of each option appear later.

record(
base-uri?as xs:boolean,
collation?as xs:string,
comments?as xs:boolean,
debug?as xs:boolean,
id-property?as xs:boolean,
idrefs-property?as xs:boolean,
in-scope-namespaces?as xs:boolean,
items-equal?as fn(item(), item()) as xs:boolean?,
map-order?as xs:boolean,
namespace-prefixes?as xs:boolean,
nilled-property?as xs:boolean,
normalization-form?as xs:string?,
ordered?as xs:boolean,
processing-instructions?as xs:boolean,
timezones?as xs:boolean,
type-annotations?as xs:boolean,
type-variety?as xs:boolean,
typed-values?as xs:boolean,
unordered-elements?as xs:QName*,
whitespace?as enum("preserve", "strip", "normalize")
)
KeyMeaning

base-uri?

Determines whether the base-uri of a node is significant.
  • Type: xs:boolean

  • Default: false()

collation?

Identifies a collation which is used at all levels of recursion when strings are compared (but not when names are compared), according to the rules in 5.3.7 Choosing a collation. If the argument is not supplied, or if it is empty, then the default collation from the dynamic context of the caller is used.
  • Type: xs:string

  • Default: fn:default-collation()

comments?

Determines whether comments are significant.
  • Type: xs:boolean

  • Default: false()

debug?

Requests diagnostics in the case where the function returns false. When this option is set and the two inputs are found to be not equal, the implementation should output messages (in an implementation-dependent format and to an implementation-dependent destination) indicating the nature of the differences that were found.
  • Type: xs:boolean

  • Default: false()

id-property?

Determines whether the id property of elements and attributes is significant.
  • Type: xs:boolean

  • Default: false()

idrefs-property?

Determines whether the idrefs property of elements and attributes is significant.
  • Type: xs:boolean

  • Default: false()

in-scope-namespaces?

Determines whether the in-scope namespaces of elements are significant.
  • Type: xs:boolean

  • Default: false()

items-equal?

A user-supplied function to test whether two items are considered equal. The function can return true or false to indicate that two items are or are not equal, overriding the normal rules that would apply to those items; or it can return an empty sequence, to indicate that the normal rules should be followed. Note that returning () is not equivalent to returning false.
  • Type: fn(item(), item()) as xs:boolean?

  • Default: fn:void#0

map-order?

Determines whether the order of entries in maps is significant.
  • Type: xs:boolean

  • Default: false()

namespace-prefixes?

Determines whether namespace prefixes in xs:QName values (particularly the names of elements and attributes) are significant.
  • Type: xs:boolean

  • Default: false()

nilled-property?

Determines whether the nilled property of elements and attributes is significant.
  • Type: xs:boolean

  • Default: false()

normalization-form?

If present, indicates that text and attributes are converted to the specified Unicode normalization form prior to comparison. The value is as for the corresponding argument of fn:normalize-unicode.
  • Type: xs:string?

  • Default: ()

ordered?

Controls whether the top-level order of the items of the input sequences is considered.
  • Type: xs:boolean

  • Default: true()

processing-instructions?

Determines whether processing instructions are significant.
  • Type: xs:boolean

  • Default: false()

timezones?

Determines whether timezones in date/time values are significant.
  • Type: xs:boolean

  • Default: false()

type-annotations?

Determines whether type annotations are significant.
  • Type: xs:boolean

  • Default: false()

type-variety?

Determines whether the variety of the type annotation of an element (whether it has complex content or simple content) is significant.
  • Type: xs:boolean

  • Default: true()

typed-values?

Determines whether nodes are compared using their typed values rather than their string values.
  • Type: xs:boolean

  • Default: true()

unordered-elements?

A list of QNames of elements considered to be unordered: that is, their child elements may appear in any order.
  • Type: xs:QName*

  • Default: ()

whitespace?

Determines the extent to which whitespace is treated as significant. The value preserve retains all whitespace. The value strip ignores text nodes consisting entirely of whitespace. The value normalize ignores whitespace text nodes in the same way as the strip option, and additionally compares text and attribute nodes after normalizing whitespace in accordance with the rules of the fn:normalize-space function. The detailed rules, given below, also take into account type annotations and xml:space attributes.
  • Type: enum("preserve", "strip", "normalize")

  • Default: preserve

Note:

As a general rule for boolean options (but not invariably), the value true indicates that the comparison is more strict.

In the following rules, where a recursive call on fn:deep-equal is made, this is assumed to use the same values of $options as the original call.

The rules reference a function equal-strings which compares two xs:string or xs:anyURI values as follows:

  1. If the whitespace option is set to normalize, then each string is processed by calling the fn:normalize-space function.

  2. If the normalization-form option is present, each string is then normalized by calling the fn:normalize-unicode function, supplying the specified normalization form.

  3. The two strings are then compared for equality under the requested collation.

More formally, the equal-strings function is equivalent to the following implementation in XQuery:

declare function equal-strings(
  $string1  as xs:string,
  $string2  as xs:string, 
  $options  as map(*)
) as xs:boolean {
  let $n1 := if ($options?normalization-form)
             then normalize-unicode(?, $options?normalization-form) 
             else identity#1
  let $n2 := if ($options?whitespace = "normalize")
             then normalize-space#1 
             else identity#1               
  return compare($n1($n2($string1)), $n1($n2($string2)), $options?collation) eq 0    
}

The rules for deciding whether two items $i1 and $i2 are deep-equal are as follows.

The two items are first compared using the function supplied in the items-equal option. If this returns true then the items are deep-equal. If it returns false then the items are not deep-equal. If it returns an empty sequence (which is always the case if the option is not explicitly specified) then the two items are deep-equal if one or more of the following conditions are true:

  1. All of the following conditions are true:

    1. $i1 is an atomic item.

    2. $i2 is an atomic item.

    3. Either the type-annotations option is false, or both atomic items have the same type annotation.

    4. One of the following conditions is true:

      1. If both $i1 and $i2 are instances of xs:string, xs:untypedAtomic, or xs:anyURI, equal-strings($i1, $i2, $collation, $options) returns true.

      2. If both $i1 and $i2 are instances of xs:date, xs:time or xs:dateTime, $i1 eq $i2 returns true.

      3. If both $i1 and $i2 are instances of xs:hexBinary or xs:base64Binary, $i1 eq $i2 returns true.

      4. Otherwise, fn:atomic-equal($i1, $i2) returns true.

      Note:

      If $i1 and $i2 are not comparable, that is, if the expression ($i1 eq $i2) would raise an error, then the function returns false; it does not report an error.

    5. One of the following conditions is true:

      1. Option namespace-prefixes is false.

      2. Neither $i1 nor $i2 is of type xs:QName or xs:NOTATION.

      3. $i1 and $i2 are qualified names with the same namespace prefix.

    6. One of the following conditions is true:

      1. Option timezones is false.

      2. Neither $i1 nor $i2 is of type xs:date, xs:time, xs:dateTime, xs:gYear, xs:gYearMonth, xs:gMonth, xs:gMonthDay, or xs:gDay.

      3. Neither $i1 nor $i2 has a timezone component.

      4. Both $i1 and $i2 have a timezone component and the timezone components are equal.

  2. All of the following conditions are true:

    1. $i1 is a map.

    2. $i2 is a map.

    3. Both maps have the same number of entries.

    4. For every entry in the first map, there is an entry in the second map that:

      1. has the same key (note that the collation is not used when comparing keys), and

      2. has the same associated value (compared using the fn:deep-equal function, recursively).

    5. Either map-order is false, or the entries in both maps appear in the same order, that is, the Nth key in the first map is the same key as the Nth key in the second map, for all N.

  3. All the following conditions are true:

    1. $i1 is an array.

    2. $i2 is an array.

    3. Both arrays have the same number of members (array:size($i1) eq array:size($i2)).

    4. Members in the same position of both arrays are deep-equal to each other: that is, every $p in 1 to array:size($i1) satisfies deep-equal($i1($p), $i2($p), $collation, $options).

  4. All the following conditions are true:

    1. $i1 is a function item and is not a map or array.

    2. $i2 is a function item and is not a map or array.

    3. $i1 and $i2 have the same function identity. The concept of function identity is explained in Section 8.1 Function ItemsDM.

  5. All the following conditions are true:

    1. $i1 is a node (specifically, an XNode).

    2. $i2 is a node (specifically, an XNode).

    3. Both nodes have the same node kind.

    4. Either the base-uri option is false, or both nodes have the same value for their base URI property, or both nodes have an absent base URI.

    5. Let significant-children($parent) be the sequence of nodes obtained by applying the following steps to the children of $parent, in turn:

      1. Comment nodes are discarded if the option comments is false.

      2. Processing instruction nodes are discarded if the option processing-instructions is false.

      3. Adjacent text nodes are merged.

      4. Whitespace-only text nodes are discarded if both the following conditions are true:

        1. The option whitespace is set to strip or normalize; and

        2. The text node is not within the scope of an element that has the attribute xml:space="preserve".

        Note:

        Whitespace text nodes will already have been discarded if $parent is a schema-validated element node whose type annotation is a complex type with an element-only or empty content model.

    6. One of the following conditions is true.

      1. Both nodes are document nodes, and the sequence significant-children($i1) is deep-equal to the sequence significant-children($i2).

      2. Both nodes are element nodes, and all the following conditions are true:

        1. The two nodes have the same name, that is (node-name($i1) eq node-name($i2)).

        2. Either the option namespace-prefixes is false, or both element names have the same prefix.

        3. Either the option in-scope-namespaces is false, or both element nodes have the same in-scope namespace bindings.

        4. Either the option type-annotations is false, or both element nodes have the same type annotation.

        5. Either the option id-property is false, or both element nodes have the same value for their is-id property.

        6. Either the option idrefs-property is false, or both element nodes have the same value for their is-idrefs property.

        7. Either the option nilled-property is false, or both element nodes have the same value for their nilled property.

        8. One of the following conditions is true:

          1. The option type-variety is false.

          2. Both nodes are annotated as having simple content. For this purpose simple content means either a simple type or a complex type with simple content.

          3. Both nodes are annotated as having complex content. For this purpose complex content means a complex type whose variety is mixed, element-only, or empty.

          Note:

          It is a consequence of this rule that, by default, validating a document D against a schema will usually (but not necessarily) result in a document that is not deep-equal to D. The exception is when the schema allows all elements to have mixed content.

        9. The two nodes have the same number of attributes, and for every attribute $a1 in $i1/@* there exists an attribute $a2 in $i2/@* such that node-name($a1) eq node-name($a2) and $a1 and $a2 are deep-equal.

          Note:

          Attributes, like other items, may be compared using the supplied items-equal function. However, this function will not be called to compare two attribute nodes unless they have the same name.

        10. One of the following conditions holds:

          1. Both element nodes are annotated as having simple content (as defined above), the typed-values option is true, and the typed value of $i1 is deep-equal to the typed value of $i2.

            Note:

            The typed value of an element node is used only when the element has simple content, which means that no error can occur as a result of atomizing a node with no typed value.

          2. Both element nodes are annotated as having simple content (as defined above), the typed-values option is false, and the equal-strings function returns true when applied to the string value of $i1 and the string value of $i2.

          3. Both element nodes have a type annotation that is a complex type with element-only, mixed, or empty content, the (common) element name is not present in the unordered-elements option, and the sequence significant-children($i1) is deep-equal to the sequence significant-children($i2).

          4. Both element nodes have a type annotation that is a complex type with element-only, mixed, or empty content, the (common) element name is present in the unordered-elements option, and the sequence significant-children($i1) is deep-equal to some permutation of the sequence significant-children($i2).

            Note:

            Elements annotated as xs:untyped fall into this category.

            Including an element name in the unordered-elements list is unlikely to be useful except when the relevant elements have element-only content, but this is not a requirement: the rules apply equally to elements with mixed content, or even (trivially) to elements with empty content.

      3. Both nodes are attribute nodes, and all the following conditions are true:

        1. The two attribute nodes have the same name, that is (node-name($i1) eq node-name($i2)).

        2. Either the option namespace-prefixes is false, or both attribute names have the same prefix.

        3. Either the option type-annotations is false, or both attribute nodes have the same type annotation.

        4. Either the option id-property is false, or both attribute nodes have the same value for their is-id property.

        5. Either the option idrefs-property is false, or both attribute nodes have the same value for their is-idrefs property.

        6. Let T be true if the option typed-value is true and both attributes $i1 and $i2 have a type annotation other than xs:untypedAtomic.

          Then either T is true and the typed value of $i1 is deep-equal to the typed value of $i2, or T is false and the equal-strings function returns true when applied to the string value of $i1 and the string value of $i2.

      4. Both nodes are processing instruction nodes, and all the following conditions are true:

        1. The two nodes have the same name, that is (node-name($i1) eq node-name($i2)).

        2. The equal-strings function returns true when applied to the string value of $i1 and the string value of $i2.

      5. Both nodes are namespace nodes, and all the following conditions are true:

        1. The two nodes either have the same name or are both nameless, that is fn:deep-equal(node-name($i1), node-name($i2)).

        2. The string value of $i1 is equal to the string value of $i2 when compared using the Unicode codepoint collation.

        Note:

        Namespace nodes are not considered directly unless they appear in the top-level sequences passed explicitly to the fn:deep-equal function.

      6. Both nodes are comment nodes, and the equal-strings function returns true when applied to their string values.

      7. Both nodes are text nodes, and the equal-strings function returns true when applied to their string values.

  6. All the following conditions are true:

    1. $i1 is a JNode.

    2. $i2 is a JNode.

    3. The ·content· property of $i1 is deep-equal to the ·content· property of $i2.

      Note:

      The other properties of the two JNodes, such as ·parent· and ·selector·, are ignored. As with XNodes, deep equality considers only the subtree rooted at the node, and not its position within a containing tree.

In all other cases the result is false.

Error Conditions

A type error is raised [err:XPTY0004]XP if the value of $options includes an entry whose key is defined in this specification, and whose value is not of the permitted type for that key.

A dynamic error is raised [err:FOJS0005] if the value of $options includes an entry whose key is defined in this specification, and whose value is not a permitted value for that key.

Notes

By default, whitespace in text nodes and attributes is considered significant. There are various ways whitespace differences can be ignored:

  • If nodes have been schema-validated, setting the typed-values option to true causes the typed values rather than the string values to be compared. This will typically cause whitespace to be ignored except where the type of the value is xs:string.

  • Setting the whitespace option to normalize causes all text and attribute nodes to have leading and trailing whitespace removed, and intermediate whitespace reduced to a single character.

By default, two nodes are not required to have the same type annotation, and they are not required to have the same in-scope namespaces. They may also differ in their parent, their base URI, and the values returned by the is-id and is-idrefs accessors (see Section 7.5.5 is-id AccessorDM and Section 7.5.6 is-idrefs AccessorDM). The order of children is significant, but the order of attributes is insignificant.

By default, the contents of comments and processing instructions are significant only if these nodes appear directly as items in the two sequences being compared. The content of a comment or processing instruction that appears as a descendant of an item in one of the sequences being compared does not affect the result. In previous versions of this specification, the presence of a comment or processing instruction, if it caused text to be split across two text nodes, might affect the result; this has been changed in 4.0 so that adjacent text nodes are merged after comments and processing instructions have been stripped.

Comparing items of different kind (for example, comparing an atomic item to a node, or a map to an array, or an integer to an xs:date) returns false, it does not return an error. So the result of fn:deep-equal(1, current-dateTime()) is false.

The items-equal callback function may be used to override the default rules for comparing individual items. For example, it might return true unconditionally when comparing two @timestamp attributes, if there is no expectation that the two trees will have identical timestamps. Given two nodes $n1 and $n2, it might compare them using the is operator, so that instead of comparing the descendants of the two nodes, the function simply checks whether they are the same node. Given two function items $f1 and $f2 it might return true unconditionally, knowing that there is no effective way to test if the functions are equivalent. Given two numeric values, it might return true if they are equal to six decimal places.

It is good practice for the items-equal callback function to be reflexive, symmetric, and transitive; if it is not, then the fn:deep-equal function itself will lack these qualities. Reflexive means that every item (including NaN) should be equal to itself; symmetric means that items-equal(A, B) should return the same result as items-equal(B, A), and transitive means that items-equal(A, B) and items-equal(B, C) should imply items-equal(A, C).

Setting the ordered option to false or supplying the unordered-elements option may result in poor performance when comparing long sequences, especially if the items-equal callback function is supplied.

Examples
Variables
let $at := <attendees>
  <name last="Parker" first="Peter"/>
  <name last="Barker" first="Bob"/>
  <name last="Parker" first="Peter"/>
</attendees>
Expression:

deep-equal($at, $at/*)

Result:
false()
Expression:

deep-equal($at/name[1], $at/name[2])

Result:
false()
Expression:

deep-equal($at/name[1], $at/name[3])

Result:
true()
Expression:

deep-equal($at/name[1], 'Peter Parker')

Result:
false()
Expression:
deep-equal(
  $at//name[@first="Bob"], 
  $at//name[@last="Barker"],
  options := { 'items-equal': op('is') } 
)
Result:
true()

(Tests whether the two input sequences contain exactly the same nodes.)

Expression:

deep-equal([ 1, 2, 3], [ 1, 2, 3 ])

Result:
true()
Expression:

deep-equal((1, 2, 3), [ 1, 2, 3 ])

Result:
false()
Expression:
deep-equal(
  { 1: 'a', 2: 'b' },
  { 2: 'b', 1: 'a' }
)
Result:
true()
Expression:
deep-equal(
  (1, 2, 3, 4),
  (1, 4, 3, 2),
  options := { 'ordered': false() }
)
Result:
true()
Expression:
deep-equal(
  (1, 1, 2, 3),
  (1, 2, 3, 3),
  options := { 'ordered': false() }
)
Result:
false()
Expression:
deep-equal(
  parse-xml("<a xmlns='AA'/>"),
  parse-xml("<p:a xmlns:p='AA'/>")
)
Result:
true()

(By default, namespace prefixes are ignored).

Expression:
deep-equal(
  parse-xml("<a xmlns='AA'/>"),
  parse-xml("<p:a xmlns:p='AA'/>"),
  options := { 'namespace-prefixes': true() }
)
Result:
false()

(False because the namespace prefixes differ).

Expression:
deep-equal(
  parse-xml("<a xmlns='AA'/>"),
  parse-xml("<p:a xmlns:p='AA'/>"),
  options := { 'in-scope-namespaces': true() }
)
Result:
false()

(False because the in-scope namespace bindings differ).

Expression:
deep-equal(
  parse-xml("<a><b/><c/></a>"),
  parse-xml("<a><c/><b/></a>")
)
Result:
false()

(By default, order of elements is significant).

Expression:
deep-equal(
  parse-xml("<a><b/><c/></a>"),
  parse-xml("<a><c/><b/></a>"),
  options := { 'unordered-elements': #a) }
)
Result:
true()

(The unordered-elements option means that the ordering of the children of a is ignored.)

Expression:
deep-equal(
  parse-xml("<para style='bold'><span>x</span></para>"),
  parse-xml("<para style=' bold'> <span>x</span></para>")
)
Result:
false()

(By default, both the leading whitespace in the style attribute and the whitespace text node preceding the span element are significant.)

Expression:
deep-equal(
  parse-xml("<para style='bold'><span>x</span></para>"),
  parse-xml("<para style=' bold'> <span>x</span></para>"),
  options := { 'whitespace': 'normalize' }
)
Result:
true()

(The whitespace option causes both the leading space in the attribute value and the whitespace preceding the span element to be ignored.)

Expression:
deep-equal(
  (1, 2, 3), 
  (1.0007, 1.9998, 3.0005),
  options := { 'items-equal': fn($x, $y) {
    if (($x, $y) instance of xs:numeric+) {
      abs($x - $y) lt 0.001
    }
  } }
)
Result:
true()

(For numeric values, the callback function tests whether they are approximately equal. For any other items, it returns an empty sequence, so the normal comparison rules apply.)

Expression:
deep-equal(
  (1, 2, 3, 4, 5), 
  (1, 2, 3, 8, 5),
  options := { 'items-equal': fn($x, $y) {
    trace((), `comparing { $x } and { $y }`)
  } }
)
Result:
false()

(The callback function traces which items are being compared, without changing the result of the comparison.)

14.2.4 fn:distinct-values

Changes in 4.0  

  1. Changed in 4.0 to use transitive equality comparisons for numeric values.

  2. The order of results is now prescribed; it was previously implementation-dependent.  [Issue 628 PR 987]

  3. Atomic items of types xs:hexBinary and xs:base64Binary are now mutually comparable. In rare cases, where an application uses both types and assumes they are distinct, this can represent a backwards incompatibility.  [Issue 2139  14 August 2025]

Summary

Returns the values that appear in a sequence, with duplicates eliminated.

Signature
fn:distinct-values(
$valuesas xs:anyAtomicType*,
$collationas xs:string?:= fn:default-collation()
) as xs:anyAtomicType*
Properties

The one-argument form of this function is deterministic, context-dependent, and focus-independent. It depends on collations, and implicit timezone.

The two-argument form of this function is deterministic, context-dependent, and focus-independent. It depends on collations, and static base URI, and implicit timezone.

Rules

The function returns the sequence that results from removing from $values all but one of a set of values that are considered equal to one another. Two items $J and $K in the input sequence (after atomization, as required by the function signature) are considered equal if fn:deep-equal($J, $K, $coll) is true, where $coll is the collation selected according to the rules in 5.3.7 Choosing a collation. This collation is used when string comparison is required.

The ordering of the result is as follows:

  • For any set of values that compare equal, the one that is returned is the one that appears first in $values.

  • The items that are returned appear in the order of their first appearance within $values.

Formal Equivalent

The effect of the function is equivalent to the result of the following XPath expression.

filter($values, 
  fn($item, $pos) {
    empty(
      filter(
        subsequence($values, 1, $pos - 1),
        deep-equal(?, $item, $collation)
      )
    )
  }
)
Notes

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

Values of type xs:untypedAtomic are compared as if they were of type xs:string.

Values that cannot be compared, because the eq operator is not defined for their types, are considered to be distinct.

For xs:float and xs:double values, positive zero is equal to negative zero and, although NaN does not equal itself, if $values contains multiple NaN values a single NaN is returned.

If xs:dateTime, xs:date or xs:time values do not have a timezone, they are considered to have the implicit timezone provided by the dynamic context for the purpose of comparison. Note that xs:dateTime, xs:date or xs:time values can compare equal even if their timezones are different.

Examples
ExpressionResult
distinct-values((1, 2.0, 3, 2))
1, 2.0, 3
distinct-values((
  xs:untypedAtomic("cherry"),
  xs:untypedAtomic("plum"),
  xs:untypedAtomic("plum")
))
xs:untypedAtomic("cherry"), xs:untypedAtomic("plum")

H Changes since 3.1 (Non-Normative)

H.1 Summary of Changes

  1. Use the arrows to browse significant changes since the 3.1 version of this specification.

    See 1 Introduction

  2. Sections with significant changes are marked Δ in the table of contents. New functions introduced in this version are marked ➕ in the table of contents.

    See 1 Introduction

  3. PR 1620 1886 

    Options are added to customize the form of the output.

    See 2.2.6 fn:path

  4. PR 1547 1551 

    New in 4.0

    See 2.2.8 fn:siblings

  5. PR 629 803 

    New in 4.0

    See 3.2.2 fn:message

  6. PR 1260 1275 

    A third argument has been added, providing control over the rounding mode.

    See 4.4.4 fn:round

  7. New in 4.0

    See 4.4.7 fn:is-NaN

  8. PR 1049 1151 

    Decimal format parameters can now be supplied directly as a map in the third argument, rather than referencing a format defined in the static context.

    See 4.7.2 fn:format-number

  9. PR 1205 1230 

    New in 4.0

    See 4.8.2 math:e

    See 4.8.16 math:sinh

    See 4.8.17 math:cosh

    See 4.8.18 math:tanh

  10. The 3.1 specification suggested that every value in the result range should have the same chance of being chosen. This has been corrected to say that the distribution should be arithmetically uniform (because there are as many xs:double values between 0.01 and 0.1 as there are between 0.1 and 1.0).

    See 4.9.2 fn:random-number-generator

  11. PR 261 306 993 

    New in 4.0

    See 5.4.1 fn:char

  12. New in 4.0

    See 5.4.2 fn:characters

  13. PR 937 995 1190 

    New in 4.0

    See 5.4.13 fn:hash

  14. New in 4.0

    See 7.6.2 fn:parse-uri

  15. PR 1423 1413 

    New in 4.0

    See 7.6.3 fn:build-uri

  16. New in 4.0

    See 11.2.6 fn:in-scope-namespaces

  17. Reformulated in 4.0 in terms of the new fn:in-scope-namespaces function; the semantics are unchanged.

    See 11.2.7 fn:in-scope-prefixes

  18. Reformulated in 4.0 in terms of the new fn:in-scope-namespaces function; the semantics are unchanged.

    See 11.2.8 fn:namespace-uri-for-prefix

  19. New in 4.0

    See 14.1.9 fn:replicate

  20. New in 4.0

    See 14.1.12 fn:slice

  21. New in 4.0. The function is identical toreplaces the internal op:same-key function in 3.1

    See 14.2.1 fn:atomic-equal

  22. PR 1120 1150 

    A callback function can be supplied for comparing individual items.

    See 14.2.2 fn:deep-equal

  23. Changed in 4.0 to use transitive equality comparisons for numeric values.

    See 14.2.4 fn:distinct-values

  24. PR 614 987 

    New in 4.0

    See 14.2.5 fn:duplicate-values

  25. New in 4.0. Originally proposed under the name fn:uniform

    See 14.4.6 fn:all-equal

  26. New in 4.0. Originally proposed under the name fn:unique

    See 14.4.7 fn:all-different

  27. PR 1117 1279 

    The $options parameter has been added.

    See 14.6.6 fn:unparsed-text-lines

  28. New in 4.0

    See 15.1.5 fn:xsd-validator

  29. PR 259 956 

    A new function is available for processing input data in HTML format.

    See 15.2 Functions on HTML Data

    New in 4.0

    See 15.2.2 fn:parse-html

  30. PR 975 1058 1246 

    An option is provided to control how JSON numbers should be formatted.

    See 15.3.4 fn:parse-json

  31. Additional options are available, as defined by fn:parse-json.

    See 15.3.5 fn:json-doc

  32. PR 533 719 834 1066 

    New in 4.0

    See 15.4.4 fn:csv-to-arrays

    See 15.4.7 fn:parse-csv

  33. PR 533 719 834 1066 1605 

    New in 4.0

    See 15.4.10 fn:csv-to-xml

  34. PR 791 1256 1282 1405 

    New in 4.0

    See 15.5.1 fn:invisible-xml

  35. New in 4.0

    See 17.2.3 fn:every

  36. New in 4.0

    See 17.2.9 fn:highest

  37. New in 4.0

    See 17.2.10 fn:index-where

  38. New in 4.0

    See 17.2.11 fn:lowest

  39. New in 4.0

    See 17.2.15 fn:scan-right

  40. New in 4.0

    See 17.2.16 fn:some

  41. PR 521 761 

    New in 4.0

    See 17.2.22 fn:transitive-closure

  42. New in 4.0

    See 18.4.6 map:filter

  43. New in 4.0

    See 18.4.10 map:items

  44. PR 478 515 

    New in 4.0

    See 18.4.12 map:keys-where

  45. PR 1575 1906 

    A new function fn:element-to-map is provided for converting XDM trees to maps suitable for serialization as JSON. Unlike the fn:xml-to-json function retained from 3.1, this can handle arbitrary XML as input.

    See 18.5 Converting elements to maps

  46. New in 4.0

    See 19.2.3 array:empty

  47. PR 968 1295 

    New in 4.0

    See 19.2.13 array:index-of

  48. PR 476 1087 

    New in 4.0

    See 19.2.16 array:items

  49. PR 360 476 

    New in 4.0

    See 19.2.18 array:members

    See 19.2.19 array:of-members

  50. New in 4.0

    See 19.2.24 array:slice

  51. New in 4.0

    See 19.2.27 array:split

  52. Supplying an empty sequence as the value of an optional argument is equivalent to omitting the argument.

    See 19.2.28 array:subarray

  53. PR 533 719 834 

    New functions are available for processing input data in CSV (comma separated values) format.

    See 15.4 Functions on CSV Data

  54. PR 289 1901 

    A third argument is added, allowing user control of how absent keys should be handled.

    See 18.4.9 map:get

    A third argument is added, allowing user control of how index-out-of-bounds conditions should be handled.

    See 19.2.11 array:get

  55. A new collation URI is defined for Unicode case-insensitive comparison and ordering.

    See 5.3.5 The Unicode case-insensitive collation

  56. The specification now describes how an initial BOM should be handled.

    See 14.6.5 fn:unparsed-text

  57. PR 1727 1740 

    It is no longer guaranteed that the new key replaces the existing key.

    See 18.4.14 map:put

  58. The function is extended to handle JNodes.

    See 2.2.6 fn:path

    Generalized to work with JNodes as well as XNodes.

    See 2.2.7 fn:has-children

    See 2.3.2 fn:innermost

    See 2.3.3 fn:outermost

  59. Atomic items of types xs:hexBinary and xs:base64Binary are now mutually comparable. In rare cases, where an application uses both types and assumes they are distinct, this can represent a backwards incompatibility.

    See 14.2.1 fn:atomic-equal

    See 14.2.2 fn:deep-equal

    See 14.2.4 fn:distinct-values

  60. PR 173 

    New in 4.0

    See 17.3.4 fn:op

  61. PR 203 

    New in 4.0

    See 18.4.1 map:build

  62. PR 207 

    New in 4.0

    See 11.1.2 fn:parse-QName

    See 11.2.5 fn:expanded-QName

  63. PR 222 

    New in 4.0

    See 14.2.7 fn:starts-with-subsequence

    See 14.2.8 fn:ends-with-subsequence

    See 14.2.9 fn:contains-subsequence

  64. PR 250 

    New in 4.0

    See 14.1.3 fn:foot

    See 14.1.15 fn:trunk

    See 19.2.2 array:build

    See 19.2.8 array:foot

    See 19.2.30 array:trunk

  65. PR 258 

    New in 4.0

    See 19.2.14 array:index-where

  66. PR 313 

    The second argument can now be a sequence of integers.

    See 14.1.8 fn:remove

  67. PR 314 

    New in 4.0

    See 18.4.4 map:entries

  68. PR 326 

    Higher-order functions are no longer an optional feature.

    See 1.2 Conformance

  69. PR 419 

    New in 4.0

    See 14.1.7 fn:items-at

  70. PR 434 

    New in 4.0

    See 4.5.2 fn:parse-integer

    The function has been extended to allow output in a radix other than 10, for example in hexadecimal.

    See 4.6.1 fn:format-integer

  71. PR 482 

    Deleted an inaccurate statement concerning the behavior of NaN.

    See 4.3 Comparison operators on numeric values

  72. PR 507 

    New in 4.0

    See 17.2.13 fn:partition

  73. PR 546 

    It is no longer automatically an error if the input contains a codepoint that is not valid in XML. Instead, the codepoint must be a permitted character. The set of permitted characters is implementation-defined, but it is recommended that all Unicode characters should be accepted.

    See 5.2.1 fn:codepoints-to-string

    It is no longer automatically an error if the resource (after decoding) contains a codepoint that is not valid in XML. Instead, the codepoint must be a permitted character. The set of permitted characters is implementation-defined, but it is recommended that all Unicode characters should be accepted.

    See 14.6.5 fn:unparsed-text

    The rules regarding use of non-XML characters in JSON texts have been relaxed.

    See 15.3.3 JSON character repertoire

    See 15.3.4 fn:parse-json

    It is no longer automatically an error if the input contains a codepoint that is not valid in XML. Instead, the codepoint must be a permitted character. The set of permitted characters is implementation-defined, but it is recommended that all Unicode characters should be accepted.

    See 15.3.5 fn:json-doc

  74. PR 631 

    New in 4.0

    See 7.3 fn:decode-from-uri

  75. PR 662 

    Constructor functions now have a zero-arity form; the first argument defaults to the context item.

    See 22 Constructor functions

  76. PR 680 

    The case-insensitive collation is now defined normatively within this specification, rather than by reference to the HTML "living specification", which is subject to change. The collation can now be used for ordering comparisons as well as equality comparisons.

    See 5.3.6 The HTML ASCII Case-Insensitive Collation

  77. PR 702 

    The function can now take any number of arguments (previously it had to be two or more), and the arguments can be sequences of strings rather than single strings.

    See 5.4.4 fn:concat

  78. PR 710 

    Changes the function to return a sequence of key-value pairs rather than a map.

    See 17.1.5 fn:function-annotations

  79. PR 727 

    It has been clarified that loading a module has no effect on the static or dynamic context of the caller.

    See 17.3.2 fn:load-xquery-module

  80. PR 795 

    New in 4.0

    See 17.2.19 fn:sort-with

  81. PR 828 

    The $predicate callback function accepts an optional position argument.

    See 17.2.4 fn:filter

    The $action callback function accepts an optional position argument.

    See 17.2.7 fn:for-each

    See 17.2.8 fn:for-each-pair

    The $predicate callback function now accepts an optional position argument.

    See 19.2.4 array:filter

    The $action callback function now accepts an optional position argument.

    See 19.2.9 array:for-each

    See 19.2.10 array:for-each-pair

  82. PR 881 

    The way that fn:min and fn:max compare numeric values of different types has changed. The most noticeable effect is that when these functions are applied to a sequence of xs:integer or xs:decimal values, the result is an xs:integer or xs:decimal, rather than the result of converting this to an xs:double

    See 14.4.3 fn:max

    See 14.4.4 fn:min

  83. PR 901 

    All three arguments are now optional, and each argument can be set to an empty sequence. Previously if $description was supplied, it could not be empty.

    See 3.1.1 fn:error

    The $label argument can now be set to an empty sequence. Previously if $label was supplied, it could not be empty.

    See 3.2.1 fn:trace

    The third argument can now be supplied as an empty sequence.

    See 5.4.6 fn:substring

    The second argument can now be an empty sequence.

    See 6.3.3 fn:tokenize

    The optional second argument can now be supplied as an empty sequence.

    See 7.1 fn:resolve-uri

    The 3rd, 4th, and 5th arguments are now optional; previously the function required either 2 or 5 arguments.

    See 10.8.1 fn:format-dateTime

    See 10.8.2 fn:format-date

    See 10.8.3 fn:format-time

    The optional third argument can now be supplied as an empty sequence.

    See 14.1.13 fn:subsequence

  84. PR 905 

    The rule that multiple calls on fn:doc supplying the same absolute URI must return the same document node has been clarified; in particular the rule does not apply if the dynamic context for the two calls requires different processing of the documents (such as schema validation or whitespace stripping).

    See 14.6.1 fn:doc

  85. PR 909 

    The function has been expanded in scope to handle comparison of values other than strings.

    See 14.2.3 fn:compare

  86. PR 924 

    Rules have been added clarifying that users should not be allowed to change the schema for the fn namespace.

    See D Schemas

  87. PR 925 

    The decimal format name can now be supplied as a value of type xs:QName, as an alternative to supplying a lexical QName as an instance of xs:string.

    See 4.7.2 fn:format-number

  88. PR 932 

    The specification now prescribes a minimum precision and range for durations.

    See 9.1.2 Limits and precision

  89. PR 933 

    When comments and processing instructions are ignored, any text nodes either side of the comment or processing instruction are now merged prior to comparison.

    See 14.2.2 fn:deep-equal

  90. PR 940 

    New in 4.0

    See 17.2.20 fn:subsequence-where

  91. PR 953 

    Constructor functions for named record types have been introduced.

    See 22.6 Constructor functions for named record types

  92. PR 962 

    New in 4.0

    See 17.2.2 fn:do-until

    See 17.2.23 fn:while-do

  93. PR 969 

    New in 4.0

    See 18.4.3 map:empty

  94. PR 980 

    Atomic items of types xs:hexBinary and xs:base64Binary are now mutually comparable.

    See 12.1.1 op:binary-equal

    See 12.1.2 op:binary-less-than

  95. PR 984 

    New in 4.0

    See 9.4.1 fn:seconds

  96. PR 987 

    The order of results is now prescribed; it was previously implementation-dependent.

    See 14.2.4 fn:distinct-values

  97. PR 1022 

    Regular expressions can include comments (starting and ending with #) if the c flag is set.

    See 6.1 Regular expression syntax

    See 6.2 Flags

  98. PR 1028 

    An option is provided to control how the JSON null value should be handled.

    See 15.3.4 fn:parse-json

  99. PR 1032 

    New in 4.0

    See 14.1.17 fn:void

  100. PR 1046 

    New in 4.0

    See 17.2.21 fn:take-while

  101. PR 1059 

    Use of an option keyword that is not defined in the specification and is not known to the implementation now results in a dynamic error; previously it was ignored.

    See 1.7 Options

  102. PR 1068 

    New in 4.0

    See 5.4.3 fn:graphemes

  103. PR 1072 

    The return type is now specified more precisely.

    See 17.3.2 fn:load-xquery-module

  104. PR 1090 

    When casting from a string to a duration or time or dateTime, it is now specified that when there are more digits in the fractional seconds than the implementation is able to retain, excess digits are truncated. Rounding upwards (which could affect the number of minutes or hours in the value) is not permitted.

    See 23.2 Casting from xs:string and xs:untypedAtomic

  105. PR 1093 

    New in 4.0

    See 5.3.9 fn:collation

  106. PR 1117 

    The $options parameter has been added.

    See 14.6.5 fn:unparsed-text

    See 14.6.7 fn:unparsed-text-available

  107. PR 1182 

    The $predicate callback function may return an empty sequence (meaning false).

    See 17.2.2 fn:do-until

    See 17.2.3 fn:every

    See 17.2.4 fn:filter

    See 17.2.10 fn:index-where

    See 17.2.16 fn:some

    See 17.2.21 fn:take-while

    See 17.2.23 fn:while-do

    See 18.4.6 map:filter

    See 18.4.12 map:keys-where

    See 19.2.4 array:filter

    See 19.2.14 array:index-where

  108. PR 1191 

    New in 4.0

    See 2.3.1 fn:distinct-ordered-nodes

    The $options parameter has been added, absorbing the $collation parameter.

    See 14.2.2 fn:deep-equal

  109. PR 1250 

    For selected properties including percent and exponent-separator, it is now possible to specify a single-character marker to be used in the picture string, together with a multi-character rendition to be used in the formatted output.

    See 4.7.2 fn:format-number

  110. PR 1257 

    The $options parameter has been added.

    See 15.1.1 fn:parse-xml

    See 15.1.2 fn:parse-xml-fragment

  111. PR 1262 

    New in 4.0

    See 5.3.10 fn:collation-available

  112. PR 1265 

    The constraints on the result of the function have been relaxed.

    See 2.1.6 fn:document-uri

  113. PR 1280 

    As a result of changes to the coercion rules, the number of supplied arguments can be greater than the number required: extra arguments are ignored.

    See 17.2.1 fn:apply

  114. PR 1288 

    Additional error conditions have been defined.

    See 15.1.1 fn:parse-xml

  115. PR 1296 

    New in 4.0

    See 17.2.14 fn:scan-left

  116. PR 1333 

    A new option is provided to allow the content of the loaded module to be supplied as a string.

    See 17.3.2 fn:load-xquery-module

  117. PR 1353 

    An option has been added to suppress the escaping of the solidus (forwards slash) character.

    See 15.3.7 fn:xml-to-json

  118. PR 1358 

    New in 4.0

    See 10.3.2 fn:unix-dateTime

  119. PR 1361 

    The term atomic value has been replaced by atomic item.

    See 1.9 Terminology

  120. PR 1393 

    Changes the function to return a sequence of key-value pairs rather than a map.

    See 17.1.5 fn:function-annotations

  121. PR 1409 

    This section now uses the term primitive type strictly to refer to the 20 atomic types that are not derived by restriction from another atomic type: that is, the 19 primitive atomic types defined in XSD, plus xs:untypedAtomic. The three types xs:integer, xs:dayTimeDuration, and xs:yearMonthDuration, which have custom casting rules but are not strictly-speaking primitive, are now handled in other subsections.

    See 23.1 Casting from primitive types to primitive types

    The rules for conversion of dates and times to strings are now defined entirely in terms of XSD 1.1 canonical mappings, since these deliver exactly the same result as the XPath 3.1 rules.

    See 23.1.2.2 Casting date/time values to xs:string

    The rules for conversion of durations to strings are now defined entirely in terms of XSD 1.1 canonical mappings, since the XSD 1.1 rules deliver exactly the same result as the XPath 3.1 rules.

    See 23.1.2.3 Casting xs:duration values to xs:string

  122. PR 1455 

    Numbers now retain their original lexical form, except for any changes needed to satisfy JSON syntax rules (for example, stripping leading zero digits).

    See 15.3.7 fn:xml-to-json

  123. PR 1473 

    New in 4.0

    See 14.1.5 fn:identity

  124. PR 1481 

    The function has been extended to handle other Gregorian types such as xs:gYearMonth.

    See 10.5.1 fn:year-from-dateTime

    See 10.5.2 fn:month-from-dateTime

    The function has been extended to handle other Gregorian types such as xs:gMonthDay.

    See 10.5.3 fn:day-from-dateTime

    The function has been extended to handle other types including xs:time.

    See 10.5.4 fn:hours-from-dateTime

    See 10.5.5 fn:minutes-from-dateTime

    The function has been extended to handle other types such as xs:gYearMonth.

    See 10.5.7 fn:timezone-from-dateTime

  125. PR 1504 

    New in 4.0

    See 14.1.11 fn:sequence-join

    Optional $separator added.

    See 19.2.17 array:join

  126. PR 1523 

    New functions are provided to obtain information about built-in types and types defined in an imported schema.

    See 21 Processing types

    New in 4.0

    See 21.1.2 fn:schema-type

    See 21.1.4 fn:atomic-type-annotation

    See 21.1.5 fn:node-type-annotation

  127. PR 1545 

    New in 4.0

    See 10.6.4 fn:civil-timezone

  128. PR 1565 

    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.

    See 15.3.4 fn:parse-json

  129. PR 1570 

    New in 4.0

    See 21.1.3 fn:type-of

  130. PR 1587 

    New in 4.0

    See 14.6.8 fn:unparsed-binary

  131. PR 1611 

    The spec has been corrected to note that the function depends on the implicit timezone.

    See 14.2.3 fn:compare

  132. PR 1671 

    New in 4.0.

    See 4.4.6 fn:divide-decimals

  133. PR 1703 

    The order of entries in maps is retained.

    See 15.3.4 fn:parse-json

    Ordered maps are introduced.

    See 18.1 Ordering of Maps

    Enhanced to allow for ordered maps.

    See 18.4.6 map:filter

    See 18.4.7 map:find

    See 18.4.8 map:for-each

    See 18.4.14 map:put

    See 18.4.15 map:remove

  134. PR 1711 

    It is explicitly stated that the limits for $precision are implementation-defined.

    See 4.4.4 fn:round

    See 4.4.5 fn:round-half-to-even

  135. PR 1727 

    For consistency with the new function map:build, the handling of duplicates may now be controlled by supplying a user-defined callback function as an alternative to the fixed values for the earlier duplicates option.

    See 18.4.13 map:merge

  136. PR 1734 

    In 3.1, given a mixed input sequence such as (1, 3, 4.2e0), the specification was unclear whether it was permitted to add the first two integer items using integer arithmetic, rather than converting all items to doubles before performing any arithmetic. The 4.0 specification is clear that this is permitted; but since the items can be reordered before being added, this is not required.

    See 14.4.2 fn:avg

    See 14.4.5 fn:sum

  137. PR 1825 

    New in 4.0

    See 17.2.12 fn:partial-apply

  138. PR 1856 

    Word boundaries can be matched. Lookahead and lookbehind assertions are supported. Assertions (including ^ and $) can no longer be followed by a quantifier.

    See 6.1 Regular expression syntax

    It is now permitted for the regular expression to match a zero-length string.

    See 6.3.2 fn:replace

    See 6.3.3 fn:tokenize

    The output of the function is extended to allow the represention of captured groups found within lookahead assertions.

    See 6.3.4 fn:analyze-string

    It is now permitted for the regular expression to match a zero-length string.

    See 6.3.4 fn:analyze-string

  139. PR 1879 

    Additional options to control DTD and XInclude processing have been added.

    See 15.1.1 fn:parse-xml

  140. PR 1897 

    The $replacement argument can now be a function that computes the replacement strings.

    See 6.3.2 fn:replace

  141. PR 1906 

    New in 4.0

    See 18.5.10 fn:element-to-map-plan

    New in 4.0.

    See 18.5.11 fn:element-to-map

  142. PR 1910 

    An $options parameter is added. Note that the rules for the $options parameter control aspects of processing that were implementation-defined in earlier versions of this specification. An implementation may provide configuration options designed to retain backwards-compatible behavior when no explicit options are supplied.

    See 14.6.1 fn:doc

    See 14.6.2 fn:doc-available

  143. PR 1991 

    Named record types used in the signatures of built-in functions are now available as standard in the static context.

    See C Built-in named record types

  144. PR 2001 

    New in 4.0.

    See 17.2.18 fn:sort-by

    See 19.2.26 array:sort-by

  145. PR 2013 

    Support for binary input has been added.

    See 15.1.1 fn:parse-xml

    See 15.1.2 fn:parse-xml-fragment

    New in 4.0

    See 15.2.3 fn:html-doc

    Support for binary input has been added.

    See 15.3.4 fn:parse-json

    New in 4.0

    See 15.4.8 fn:csv-doc

  146. PR 2030 

    This description of the XSD validation process was previously found (with some duplication) in the XQuery and XSLT specifications; those specifications now reference this description. As a side-effects, the descriptions of the process in XQuery and XSLT are better aligned.

    See 15.1.4 XSD validation

  147. PR 2031 

    Introduced the concept of JNodes.

    See 20 Processing JNodes

    New in 4.0

    See 20.1.1 fn:jtree

    See 20.1.3 fn:jnode-selector

    See 20.1.4 fn:jnode-position

I Backward compatibility (Non-Normative)

This section summarizes the extent to which this specification is compatible with previous versions.

Version 4.0 of this function library is fully backwards compatible with version 3.1, except as noted below:

  1. In fn:deep-equal, and in other functions such as fn:distinct-values that refer to fn:deep-equal, the rules for comparing values of different numeric types (for example, xs:double and xs:decimal) have changed. In previous versions of the specification, xs:decimal values were converted to xs:double, leading to a possible loss of precision. This could make comparisons non-transitive, leading to problems when grouping, and potentially (depending on the sort algorithm) with sorting. The problem has been fixed by requiring comparisons to be performed based on the exact mathematical value without any loss of precision.

    This means, for example, that deep-equal(0.2, 0.2e0) is now false, whereas in previous versions it was true. The two values are not mathematically equal, because the exact decimal equivalent of the xs:double value written as 0.2e0 is 0.200000000000000011102230246251565404236316680908203125.

    The corresponding change has not been made to the = and eq operators, because it was found to be too disruptive. For example, if the context node is the element <e price="10.0" discount="0.2"/>, there is an expectation that the expression @price - @discount = 9.8 should return true. But (assuming untyped data), the result of the subtraction is an xs:double whose precise value is 9.800000000000000710542735760100185871124267578125, so comparing the two values as decimals would return false.

  2. In previous versions, unrecognized options supplied to the $options parameter of functions such as fn:parse-json were silently ignored. In 4.0, they are rejected as a type error, unless they are QNames with a non-absent namespace, or are extensions recognized by the implementation.

  3. In version 4.0, omitting the $value of fn:error has the same effect as setting it to an empty sequence. In 3.1, the effects could be different (the effect of omitting the argument was implementation-defined).

  4. In version 3.1, the fn:deep-equal function did not merge adjacent text nodes after stripping comments and processing instructions, so the elements <a>abc<!--note1-->def</code> and <a>abcde<!--note2-->f</code> were considered non-equal. In version 4.0, the text nodes are now merged prior to comparison, so these two elements compare equal.

  5. In version 3.1, the atomic types xs:hexBinary and xs:base64Binary were not mutually comparable under the eq operator, and always compared not equal as map keys or under operations such as fn:distinct-values and fn:deep-equal. In version 4.0, instances of xs:hexBinary and xs:base64Binary are equal if they represent the same octet sequence. This means, for example, that the zero-length values xs:hexBinary("") and xs:base64Binary("") can no longer co-exist as keys in the same map.

  6. The format of numeric values in the output of fn:xml-to-json may be different. In version 3.1, the supplied value was parsed as an xs:double and then serialized using the casting rules, resulting in an input value of 10000000 being output as 1e7. In version 4.0, the value is output as is, except for any changes (such as stripping of leading zeroes or a leading plus sign) that might be needed to ensure the result is valid JSON.

  7. In version 4.0, the function signature of fn:namespace-uri-for-prefix constrains the first argument to be either an xs:NCName or a zero-length string (the new coercion rules mean that any string in the form of an xs:NCName is acceptable). If a string is supplied that does not meet these requirements, a type error will be raised. In version 3.1, this was not an error: it came under the rule that when no namespace binding existed for the supplied prefix, the function would return an empty sequence.

    Furthermore, because the expected type of this parameter is no longer xs:string, the special coercion rules for xs:string parameters in XPath 1.0 compatibility mode no longer apply. For example, supplying xs:duration('PT1H') as the first argument will now raise a type error, rather than looking for a namespace binding for the prefix PT1H.

  8. Version 4.0 makes it clear that the casting of a value other than xs:string or xs:untypedAtomic to a list type (whether using a cast expression or a constructor function) is a type error [err:XPTY0004]XP. Previously this was defined as an error, but the kind of error and the error code were left unspecified. Accordingly, the function signatures of the constructor functions for built-in list types have been changed to use an argument type of xs:string?.

  9. The way that fn:min and fn:max compare numeric values of different types has changed. The most noticeable effect is that when these functions are applied to a sequence of xs:integer or xs:decimal values, the result is an xs:integer or xs:decimal, rather than the result of converting this to an xs:double.

  10. The type of the third argument of fn:format-number has changed from xs:string to (xs:string | xs:QName). Because the expected type of this parameter is no longer xs:string, the special coercion rules for xs:string parameters no longer apply. For example, it is no longer possible to supply an instance of xs:anyURI or (when XPath 1.0 compatibility mode is in force) an instance of xs:boolean or xs:duration.

  11. When map:put replaces an entry in a map with a new value for an existing key, in the case where the existing key and the new key differ (for example, if they have different type annotations), it is no longer guaranteed that the new entry includes the new key rather than the existing key.

  12. In regular expressions, the assertions ^ and $ can no longer be followed by a quantifier. This is because (a) a quantifier that allows zero occurrences means that the assertion will always match, and (b) a quantifier that allows multiple occurrences has no effect. Processors may provide an option that allows such regular expressions to be accepted for compatibility reasons.

For compatibility issues regarding earlier versions, see the 3.1 version of this specification.