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.
Copyright © 2000 W3C® (MIT, ERCIM, Keio, Beihang). W3C liability, trademark and document use rules apply.
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.
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.
The publications of this community group are dedicated to our co-chair, Michael Sperberg-McQueen (1954–2024).
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.
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.
| Function | Meaning |
|---|---|
map:build | Returns a map that typically contains one entry for each item in a supplied input sequence. |
map:contains | Tests whether a supplied map contains an entry for a given key. |
map:empty | Returns true if the supplied map contains no entries. |
map:entries | Returns a sequence containing all the key-value pairs present in a map, each represented as a ·singleton map·. |
map:entry | Returns a ·singleton map· that represents a single key-value pair. |
map:filter | Selects entries from a map, returning a new map. |
map:find | Searches 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-each | Applies a supplied function to every entry in a map, returning the sequence concatenationXP of the results. |
map:get | Returns the value associated with a supplied key in a given map. |
map:items | Returns a sequence containing all the values present in a map, in order. |
map:keys | Returns a sequence containing all the keys present in a map. |
map:keys-where | Returns a sequence containing selected keys present in a map. |
map:merge | Returns a map that combines the entries from a number of existing maps. |
map:of-pairs | Returns a map that combines data from a sequence of ·key-value pair maps·. |
map:pair | Returns a ·key-value pair map· that represents a single key-value pair. |
map:pairs | Returns a sequence containing all the key-value pairs present in a map, each represented as a ·key-value pair map·. |
map:put | Returns 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:remove | Returns a map containing all the entries from a supplied map, except those having a specified key. |
map:replace | Returns a map based on the contents of an existing map, computing a new value to be associated with a supplied key. |
map:size | Returns the number of entries in the supplied map. |
Returns a map that combines the entries from a number of existing maps.
map:merge( | ||
$maps | as , | |
$options | as | := {} |
) as | ||
This function is ·deterministic·, ·context-independent·, and ·focus-independent·.
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:
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·.
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.
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.
The $options argument can be used to control 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( | |
duplicates? | as xs:string |
) | |
| Key | Value | Meaning |
|---|---|---|
| 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·.
| |
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). | |
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"))
)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.
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.
| Variables | |
|---|---|
let $week := {
0: "Sonntag", 1: "Montag", 2: "Dienstag", 3: "Mittwoch",
4: "Donnerstag", 5: "Freitag", 6: "Samstag"
} | |
| Expression: |
|
|---|---|
| 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 |
| 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 |
| 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 |
| 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 |
| 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" |
Returns a map that combines data from a sequence of ·key-value pair maps·.
map:of-pairs( | ||
$input | as key-value-pair*, | |
$options | as | := {} |
) as | ||
This function is ·deterministic·, ·context-independent·, and ·focus-independent·.
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()*)? |
) | |
| Key | Meaning |
|---|---|
| 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.
|
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)
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.
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.
| Variables | |
|---|---|
let $week := {
0: "Sonntag", 1: "Montag", 2: "Dienstag", 3: "Mittwoch",
4: "Donnerstag", 5: "Freitag", 6: "Samstag"
} | |
| Expression: |
|
|---|---|
| Result: | {}(Returns an empty map). |
| Expression: |
|
| Result: | {
0: "Sonntag",
1: "Montag",
2: "Dienstag",
3: "Mittwoch",
4: "Donnerstag",
5: "Freitag",
6: "Samstag"
}(The function |
| 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 |
| 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 |
| 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 |
| 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 |
| 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})) | |