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 2 February13 March 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 using HTML5 vocabulary, XML function catalog, and HTML with change markings relative to version 3.0.


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


17 Maps

Maps were introduced as a new datatype in XDM 3.1. This section describes functions that operate on maps.

A map is a kind of item.

[Definition] A map consists of a sequence of entries, also known as key-value pairs. Each entry comprises a key which is an arbitrary atomic item, and an arbitrary sequence called the associated value.

[Definition] Within a map, no two entries have the same key. Two atomic items K1 and K2 are the same key for this purpose if the function call fn:atomic-equal($K1, $K2) returns true.

It is not necessary that all the keys in a map should be of the same type (for example, they can include a mixture of integers and strings).

Maps are immutable, and have no identity separate from their content. For example, the map:remove function returns a map that differs from the supplied map by the omission (typically) of one entry, but the supplied map is not changed by the operation. Two calls on map:remove with the same arguments return maps that are indistinguishable from each other; there is no way of asking whether these are “the same map”.

A map can also be viewed as a function from keys to associated values. To achieve this, a map is also a function item. The function corresponding to the map has the signature function($key as xs:anyAtomicValue) as item()*. Calling the function has the same effect as calling the map:get function: the expression $map($key) returns the same result as get($map, $key). For example, if $books-by-isbn is a map whose keys are ISBNs and whose assocated values are book elements, then the expression $books-by-isbn("0470192747") returns the book element with the given ISBN. The fact that a map is a function item allows it to be passed as an argument to higher-order functions that expect a function item as one of their arguments.

17.4 Functions that Operate on Maps

The functions defined in this section use a conventional namespace prefix map, which is assumed to be bound to the namespace URI http://www.w3.org/2005/xpath-functions/map.

The function call map:get($map, $key) can be used to retrieve the value associated with a given key.

There is no operation to atomize a map or convert it to a string. The function fn:serialize can in some cases be used to produce a JSON representation of a map.

FunctionMeaning
map:buildReturns a map that typically contains one entry for each item in a supplied input sequence.
map:containsTests whether a supplied map contains an entry for a given key.
map:emptyReturns true if the supplied map contains no entries.
map:entriesReturns a sequence containing all the key-value pairs present in a map, each represented as a ·singleton map·.
map:entryReturns a ·singleton map· that represents a single key-value pair.
map:filterSelects entries from a map, returning a new map.
map:findSearches the supplied input sequence and any contained maps and arrays for a map entry with the supplied key, and returns the corresponding values.
map:for-eachApplies a supplied function to every entry in a map, returning the sequence concatenationXP of the results.
map:getReturns the value associated with a supplied key in a given map.
map:itemsReturns a sequence containing all the values present in a map, in order.
map:keysReturns a sequence containing all the keys present in a map.
map:keys-whereReturns a sequence containing selected keys present in a map.
map:mergeReturns a map that combines the entries from a number of existing maps.
map:of-pairsReturns a map that combines data from a sequence of ·key-value pair maps·.
map:pairReturns a ·key-value pair map· that represents a single key-value pair.
map:pairsReturns a sequence containing all the key-value pairs present in a map, each represented as a ·key-value pair map·.
map:putReturns a map containing all the contents of the supplied map, but with an additional entry, which replaces any existing entry for the same key.
map:removeReturns a map containing all the entries from a supplied map, except those having a specified key.
map:replaceReturns a map based on the contents of an existing map, computing a new value to be associated with a supplied key.
map:sizeReturns the number of entries in the supplied map.

17.4.13 map:merge

Summary

Returns a map that combines the entries from a number of existing maps.

Signature
map:merge(
$mapsas map(*)*,
$optionsas map(*)?:= {}
) as map(*)
Properties

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

Rules

The function map:mergereturns a map that is formed by combining the contents of the maps supplied in the $maps argument.

Informally, the supplied maps are combined as follows:

  1. There is one entry in the returned map for each distinct key present in the union of the input maps, where two keys are distinct if they are not the ·same key·.

  2. If there are duplicate keys, that is, if two or more maps contain entries having the ·same key·, then the way this is handled is controlled by the second ($options) argument.

The definitive specification is as follows.

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

  2. The $options argument can be used to control the way in which duplicate keys are handled. The ·option parameter conventions· apply.

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

    record(
    duplicates?as xs:string
    )
    KeyValueMeaning

    duplicates?

    Determines the policy for handling duplicate keys: specifically, the action to be taken if two maps in the input sequence $maps contain entries with key values K1 and K2 where K1 and K2 are the ·same key·.
    • 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, all but the first of a set of duplicates are ignored, where the ordering is based on the order of maps in the $maps argument.
    use-last If duplicate keys are present, all but the last of a set of duplicates are ignored, where the ordering is based on the order of maps in the $maps argument.
    use-any If duplicate keys are present, all but one of a set of duplicates are ignored, and it is ·implementation-dependent· which one is retained.
    combine If duplicate keys are present, the result map includes an entry for the key whose associated value is the sequence concatenationXP of all the values associated with the key, retaining order based on the order of maps in the $maps argument. The key value in the result map that corresponds to such a set of duplicates must be the ·same key· as each of the duplicates, but it is otherwise unconstrained: for example if the duplicate keys are xs:byte(1) and xs:short(1), the key in the result could legitimately be xs:long(1).
Formal Equivalent

The effect of the function is equivalent to the result of the following XPath expression, except in error cases.

let $FOJS0003 := QName("http://www.w3.org/2005/xqt-errors", "FOJS0003")
let $duplicates-handler := {
  "use-first": fn($a, $b) { $a },
  "use-last":  fn($a, $b) { $b },
  "combine":   fn($a, $b) { $a, $b },
  "reject":    fn($a, $b) { fn:error($FOJS0003) },
  "use-any":   fn($a, $b) { fn:random-number-generator()?permute(($a, $b))[1] }
}
let $combine := fn($A as map(*), $B as map(*), $deduplicator as fn(*)) {
  fold-left(map:keys($B), $A, fn($z, $k) { 
    if (map:contains($z, $k))
    then map:put($z, $k, $deduplicator($z($k), $B($k)))
    else map:put($z, $k, $B($k))
  })
}
return fold-left($maps, dm:empty-map($options?ordering otherwise "undefined"),
  $combine(?, ?, $duplicates-handler($options?duplicates otherwise "use-first"))
)
let $FOJS0003 := QName("http://www.w3.org/2005/xqt-errors", "FOJS0003")
let $duplicates-handler := {
  "use-first": fn($a, $b) { $a },
  "use-last":  fn($a, $b) { $b },
  "combine":   fn($a, $b) { $a, $b },
  "reject":    fn($a, $b) { fn:error($FOJS0003) },
  "use-any":   fn($a, $b) { fn:random-number-generator()?permute(($a, $b))[1] }
}
let $combine := fn($A as map(*), $B as map(*), $deduplicator as fn(*)) {
  fold-left(map:keys($B), $A, fn($z, $k) { 
    if (map:contains($z, $k))
    then map:put($z, $k, $deduplicator($z($k), $B($k)))
    else map:put($z, $k, $B($k))
  })
}
return fold-left($maps, {},
  $combine(?, ?, $duplicates-handler($options?duplicates otherwise "use-first"))
)
Error Conditions

An error is raised [err:FOJS0003] if the value of $options indicates that duplicates are to be rejected, and a duplicate key is encountered.

An 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

Note:

By way of explanation, $combine is a function that combines two maps by iterating over the keys of the second map, adding each key and its corresponding value to the first map as it proceeds. The second call of fn:fold-left in the return clause then iterates over the maps supplied in the call to map:merge, accumulating a single map that absorbs successive maps in the input sequence by calling $combine.

This algorithm processes the supplied maps in a defined order, but processes the keys within each map in implementation-dependent order.

The use of fn:random-number-generator represents one possible conformant implementation for "duplicates": "use-any", but it is not the only conformant implementation and is not intended to be a realistic implementation. The purpose of this option is to allow the implementation to use whatever strategy is most efficient; for example, if the input maps are processed in parallel, then specifying "duplicates": "use-any" means that the implementation does not need to keep track of the original order of the sequence of input maps.

If the input is an empty sequence, the result is an empty map.

If the input is a sequence of length one, the result map is indistinguishable from the supplied map.

There is no requirement that the supplied input maps should have the same or compatible types. The type of a map (for example map(xs:integer, xs:string)) is descriptive of the entries it currently contains, but is not a constraint on how the map may be combined with other maps.

Examples
Variables
let $week := {
  0: "Sonntag", 1: "Montag", 2: "Dienstag", 3: "Mittwoch",
  4: "Donnerstag", 5: "Freitag", 6: "Samstag"
}
Expression:

map:merge(())

Result:
{}

(Returns an empty map).

Expression:
map:merge((
  map:entry(0, "no"),
  map:entry(1, "yes")
))
Result:
{ 0: "no", 1: "yes" }

(Returns a map with two entries).

Expression:
map:merge(
  ($week, { 7: "Unbekannt" })
)
Result:
{ 0: "Sonntag", 1: "Montag", 2: "Dienstag", 3: "Mittwoch",
  4: "Donnerstag", 5: "Freitag", 6: "Samstag", 7: "Unbekannt" }

(The value of the existing map is unchanged; the returned map contains all the entries from $week, supplemented with an additional entry.)

Expression:
map:merge(
  ($week, { 6: "Sonnabend" }),
  { "duplicates": "use-last" }
)
Result:
{ 0: "Sonntag", 1: "Montag", 2: "Dienstag", 3: "Mittwoch",
  4: "Donnerstag", 5: "Freitag", 6: "Sonnabend" }

(The value of the existing map is unchanged; the returned map contains all the entries from $week, with one entry replaced by a new entry. Both input maps contain an entry with the key 6; the one used in the result is the one that comes last in the input sequence.)

Expression:
map:merge(
  ($week, { 6: "Sonnabend" }),
  { "duplicates": "use-first" }
)
Result:
{ 0: "Sonntag", 1: "Montag", 2: "Dienstag", 3: "Mittwoch",
  4: "Donnerstag", 5: "Freitag", 6: "Samstag" }

(The value of the existing map is unchanged; the returned map contains all the entries from $week, with one entry replaced by a new entry. Both input maps contain an entry with the key 6; the one used in the result is the one that comes first in the input sequence.)

Expression:
map:merge(
  ($week, { 6: "Sonnabend" }),
  { "duplicates": "combine" }
)
Result:
{ 0: "Sonntag", 1: "Montag", 2: "Dienstag", 3: "Mittwoch",
  4: "Donnerstag", 5: "Freitag", 6: ("Samstag", "Sonnabend") }

(The value of the existing map is unchanged; the returned map contains all the entries from $week, with one entry replaced by a new entry. Both input maps contain an entry with the key 6; the entry that appears in the result is the sequence concatenationXP of the entries in the input maps, retaining order.)

Expression:
map:merge(({ "red": 0 }, { "green": 1}, { "blue": 2 }),
    { "retain-order": true() } => map:keys()
map:merge(({ "red": 0 }, { "green": 1}, { "blue": 2 })) 
                  => map:keys()
Result:
"red", "green", "blue"

17.4.14 map:of-pairs

Changes in 4.0  

  1. New in 4.0

Summary

Returns a map that combines data from a sequence of ·key-value pair maps·.

Signature
map:of-pairs(
$inputas key-value-pair*,
$optionsas map(*):= {}
) as map(*)
Properties

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

Rules

The function map:of-pairsreturns a map that is formed by combining ·key-value pair maps· supplied in the $input argument.

The $options argument can be used to control the ordering of the result, and the way in which duplicate keys are handled. The ·option parameter conventions· apply.

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

record(
combine?as (fn($existing-value as item()*, $new-value as item()*) as item()*)?
)
KeyMeaning

combine?

A function that is used to combine two different values that are supplied for the same key. The default is to combine the two values using sequence concatenationXP, retaining their order in the input sequence.
  • Type: (fn($existing-value as item()*, $new-value as item()*) as item()*)?

  • Default: fn:op(',')

Formal Equivalent

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

map:build($input, map:get(?, 'key'), map:get(?, 'value'), $combine)
Error Conditions

The function can be made to fail with a dynamic error in the event that duplicate keys are present in the input sequence by supplying a $combine function that invokes the fn:error function.

Notes

If the input is an empty sequence, the result is an empty map.

There is no requirement that the supplied key-value pairs should have the same or compatible types. The type of a map (for example map(xs:integer, xs:string)) is descriptive of the entries it currently contains, but is not a constraint on how the map may be combined with other maps.

Examples
Variables
let $week := {
  0: "Sonntag", 1: "Montag", 2: "Dienstag", 3: "Mittwoch",
  4: "Donnerstag", 5: "Freitag", 6: "Samstag"
}
Expression:

map:of-pairs(())

Result:
{}

(Returns an empty map).

Expression:

map:of-pairs(map:pairs($week))

Result:
{
  0: "Sonntag",
  1: "Montag", 
  2: "Dienstag",
  3: "Mittwoch", 
  4: "Donnerstag",
  5: "Freitag", 
  6: "Samstag"
}

(The function map:of-pairs is the inverse of map:pairs.)

Expression:
map:of-pairs((
  { "key": 0, "value": "no" },
  { "key": 1, "value": "yes" }
))
Result:
{ 0: "no", 1: "yes" }

(Returns a map with two entries).

Expression:
map:of-pairs((
  map:pairs($week),
  { "key": 7, "value": "Unbekannt" }
))
Result:
{ 0: "Sonntag", 1: "Montag", 2: "Dienstag", 3: "Mittwoch",
  4: "Donnerstag", 5: "Freitag", 6: "Samstag", 7: "Unbekannt" }

(The value of the existing map is unchanged; the returned map contains all the entries from $week, supplemented with an additional entry.)

Expression:
map:of-pairs((
  map:pairs($week),
  { "key": 6, "value": "Sonnabend" }
))
Result:
{ 0: "Sonntag", 1: "Montag", 2: "Dienstag", 3: "Mittwoch",
  4: "Donnerstag", 5: "Freitag", 6: ("Samstag", "Sonnabend") }

(The value of the existing map is unchanged; the returned map contains all the entries from $week, with one entry replaced by a new entry. Both input maps contain an entry with the key 6; the one used in the result combines the two supplied values into a single sequence.)

Expression:
map:of-pairs(
  (map:pairs($week), { "key": 6, "value": "Sonnabend" }),
  fn($old, $new) { $new }
)
Result:
{ 0: "Sonntag", 1: "Montag", 2: "Dienstag", 3: "Mittwoch",
  4: "Donnerstag", 5: "Freitag", 6: "Sonnabend" }

(The value of the existing map is unchanged; the returned map contains all the entries from $week, with one entry replaced by a new entry. Both input maps contain an entry with the key 6; the supplied $combine function ensures that the one used in the result is the one that comes last in the input sequence.)

Expression:
map:of-pairs(
  (map:pairs($week), { "key": 6, "value": "Sonnabend" }),
  fn($old, $new) { `{ $old }|{ $new }` }
)
Result:
{ 0: "Sonntag", 1: "Montag", 2: "Dienstag", 3: "Mittwoch",
  4: "Donnerstag", 5: "Freitag", 6: "Samstag|Sonnabend" }

(In the result map, the value for key 6 is obtained by concatenating the values from the two input maps, with a separator character.)

Expression:
map:of-pairs((map:pair("red": 0), map:pair("green": 1), map:pair("blue": 2 )) 
        => map:keys()
Result:
"red", "green", "blue"

(The keys are returned in the order supplied.)

Expression:
map:of-pairs((map:pair("red": 0), map:pair("green": 1), map:pair("blue": 2 )) 
        => map:put("yellow": -1) => map:keys()
{ "red": 0, "green": 1, "blue": 2 }
                  => map:pairs() => sort(keys := fn{ ?key }) => map:of-pairs()) 
        => map:keys()
Result:
"blue", "green", "red"

(Takes any map and produces a map with the same entries, but sorted by key.)

Expression:
map:of-pairs((map:pair("red": 0), map:pair("green": 1), map:pair("blue": 2 )) 
        => map:put("yellow": -1) => map:keys()
Result:
"red", "green", "blue", "yellow"

(New entries are added at the end.)

The following expression takes an existing map and sorts its entries into key order:

map:of-pairs(map:pairs($M) => sort(keys:=fn{?key}))