From e9dca5795b250adec397d2b02c039b1dab59c323 Mon Sep 17 00:00:00 2001 From: Michael Kay Date: Mon, 25 Nov 2024 18:21:53 +0000 Subject: [PATCH] Ordered Maps --- .../src/xpath-datamodel.xml | 68 ++- .../src/function-catalog.xml | 512 ++++++++++++++++-- .../src/xpath-functions.xml | 80 ++- specifications/xquery-40/src/expressions.xml | 28 +- .../xslt-40/src/element-catalog.xml | 7 + specifications/xslt-40/src/xslt.xml | 7 + .../src/xslt-xquery-serialization.xml | 24 +- 7 files changed, 657 insertions(+), 69 deletions(-) diff --git a/specifications/xpath-datamodel-40/src/xpath-datamodel.xml b/specifications/xpath-datamodel-40/src/xpath-datamodel.xml index e5bebcd7bc..c8007552e7 100644 --- a/specifications/xpath-datamodel-40/src/xpath-datamodel.xml +++ b/specifications/xpath-datamodel-40/src/xpath-datamodel.xml @@ -1511,18 +1511,36 @@ must equal the function’s arity. Constructors are added, and the single accessor function is now an iterator over the key/value pairs in the map. + Ordered maps are introduced.

A map item is a value that represents a map (in other languages this is sometimes called a hash, dictionary, or associative array). - A map is logically a collection of + A map is logically a sequence of key/value pairs. Each key in the map is unique (there is no other key to which it is equal) and has associated with it a value that is a sequence of zero or more items. There is no uniqueness constraint on -values. The semantics of equality are described in +values, only on keys. The semantics of equality when comparing keys are described in .

+

A has +a property called its ordering, which takes one of the three values +random, sorted, or fifo.

+ + +

Random ordering means that the order of entries + in the map is .

+

Sorted ordering means that the keys in the map + are considered to be sorted, and entries are retrieved in order of their keys.

+

Fifo (first-in, first-out) order means that the map + maintains an ordering of entries based on the order in which entries were added, + with new entries being added at the end, after existing entries.

+
+ +

The order of entries in a map + (which is dependent on its ordering + property) is referred to as entry order.

@@ -1538,13 +1556,20 @@ values. The semantics of equality are described in empty-map Constructor - + + +

The dm:empty-map constructor returns a map containing no key/value pairs.

-

The function is exposed in XPath as an empty map constructor, which may be written {} - or map {}.

+

The ordering property of the map is based on the + value of the $ordering argument.

+ +

In XPath an empty map constructor, written as {} + or map {}, creates a map with ordering=random. An empty map with + ordering sorted or fifo can be constructed using functions such as + map:build, map:merge, or map:of-pairs.

@@ -1565,6 +1590,32 @@ values. The semantics of equality are described in

One key/value pair whose key is $key and whose associated value is $value.

+

The ordering property of the returned map is the same + as the ordering of the supplied $map.

+ +

The detailed effect of the function depends on the ordering property, as follows:

+ + +

If the ordering is random, the order of entries in the returned + map is , and bears no necessary relationship + to the ordering of entries in the supplied $map.

+

If the ordering is sorted, the key of the new entry must be + with the keys of existing entries (a dynamic error occurs if this is not + the case), and the ordering of entries in the returned map is such that an entry with key K1 + precedes an entry with key K2 if and only + if fn:compare(K1, K2, $CC) lt 0, + where $CC is the Unicode codepoint collation.

+

Two atomic items + K1 and K2 are strictly comparable if + (a) the function call fn:compare(K1, K2, $CC) (where $CC + is the Unicode codepoint collation) does not fail with a type error, and (b) if one of the values + has a timezone component, then the other also has a timezone component.

+

If the ordering is fifo, then the order of entries in the returned + map reflects the order of entries in the supplied $map. If the key of + the new entry was present in $map then the new entry replaces that entry retaining + its current position; otherwise, the new entry is added after all existing entries.

+
+

The function is exposed in XPath through the function map:put.

@@ -1578,9 +1629,10 @@ values. The semantics of equality are described in -

The dm:iterate-map accessor calls the supplied $action - function once for each key/value pair in $map, in implementation-dependent order, - and returns the sequence concenation of the results.

+

The dm:iterate-map accessor calls the supplied $action + function once for each key/value pair in $map, in order, + and returns the sequence concenation of the results. The order in which entries + are processed reflects the property of the map.

The function is exposed in XPath most directly through the function map:for-each, but it also underpins all other functions giving access to maps, such as map:size, diff --git a/specifications/xpath-functions-40/src/function-catalog.xml b/specifications/xpath-functions-40/src/function-catalog.xml index 45f2e37ab3..9a8ae8ee3c 100644 --- a/specifications/xpath-functions-40/src/function-catalog.xml +++ b/specifications/xpath-functions-40/src/function-catalog.xml @@ -22740,6 +22740,29 @@ return node-type-annotation($x/*)]]> + + Determines the ordering, and the , of the + entries in the returned map. + + enum("random", "sorted", "fifo") + random + + + The ordering property of the returned map is random, and its + is . + + + The ordering property of the returned map is sorted, and its + is sorted by key. A dynamic error occurs + if the keys are not . + + + The ordering property of the returned map is fifo, and its + reflects the order of the maps supplied in $maps, + and within each input map, the of the entries in that map. + + + @@ -22764,7 +22787,7 @@ let $combine := fn($A as map(*), $B as map(*), $deduplicator as fn(*)) { else map:put($z, $k, $B($k)) }) } -return fold-left($maps, {}, +return fold-left($maps, dm:empty-map($options?ordering otherwise "random"), $combine(?, ?, $duplicates-handler($options?duplicates otherwise "use-first")) ) @@ -22777,6 +22800,9 @@ return fold-left($maps, {}, /> 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.

+

An error is raised if the option + ordering=sorted is requested, and the keys of the entries to be included in the result are not + .

@@ -22805,7 +22831,8 @@ return fold-left($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 +

Except when ordering=sorted, 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.

@@ -22876,6 +22903,18 @@ return fold-left($maps, {}, entry that appears in the result is the sequence concatenation of the entries in the input maps, retaining order. + + map:merge(({ "red": 0 }, { "green": 1}, { "blue": 2 }), + { "ordering": "sorted" } => map:keys() + "blue", "green", "red" + The result is in sorted order. + + + map:merge(({ "red": 0 }, { "green": 1}, { "blue": 2 }), + { "ordering": "fifo" } => map:keys() + "red", "green", "blue" + The keys are in first-in, first-out order. + @@ -22888,7 +22927,7 @@ return fold-left($maps, {}, type="record(key as xs:anyAtomicType, value as item()*)*" usage="inspection" example="{ 'key':'n','value':false() }, { 'key':'y','value':true() }"/> - + @@ -22908,9 +22947,48 @@ return fold-left($maps, {}, $input argument.

-

The optional $combine argument can be used to define how - duplicate keys should be handled. The default is to form the sequence concatenation - of the corresponding values, retaining their order in the input sequence.

+

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:

+ + + + 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 + , retaining their order + in the input sequence. + + (fn(item()*, item()*) as item()*)? + fn:op(',') + + + Determines the ordering, and the , of the + entries in the returned map. + + enum("random", "sorted", "fifo") + random + + + The ordering property of the returned map is random, and its + is . + + + The ordering property of the returned map is sorted, and its + is sorted by key. A dynamic error occurs + if the keys are not . + + + The ordering property of the returned map is fifo, and its + reflects the order of the items supplied in $input. + + + + + + @@ -22918,6 +22996,10 @@ return fold-left($maps, {}, map:build($input, map:get(?, 'key'), map:get(?, 'value'), $combine) +

An error is raised if the option + ordering=sorted is requested, and the keys of the entries to be included in the result are not + .

+

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.

@@ -23007,6 +23089,20 @@ map:build($input, map:get(?, 'key'), map:get(?, 'value'), $combine) In the result map, the value for key 6 is obtained by concatenating the values from the two input maps, with a separator character. + + + map:of-pairs((map:pair("red": 0), map:pair("green": 1), map:pair("blue": 2 )), + { "ordering": "sorted" } => map:keys() + "blue", "green", "red" + The result is in sorted order. + + + + map:of-pairs((map:pair("red": 0), map:pair("green": 1), map:pair("blue": 2 )), + { "ordering": "fifo" } => map:keys() + "red", "green", "blue" + The keys are in first-in, first-out order. + @@ -23032,13 +23128,13 @@ map:build($input, map:get(?, 'key'), map:get(?, 'value'), $combine)

Informally, the function map:keys takes any map as its $map argument and returns - the keys that are present in the map as a sequence of atomic items, in implementation-dependent order.

-

The function is nondeterministic with respect to ordering + the keys that are present in the map as a sequence of atomic items, + in .

+
map:for-each($map, fn($key, $value) { $key }) @@ -23050,11 +23146,21 @@ map:build($input, map:get(?, 'key'), map:get(?, 'value'), $combine) - map:keys({ 1: "yes", 2: "no" }) - (1, 2) + map:keys({ 1: "yes", 0: "no" }) + (1, 0) The result is in implementation-dependent order. + + map:keys({ 1: "yes", 0: "no" } => map:sort()) + (0, 1) + The map is sorted, so the result is in sorted order. + + + map:keys(map:merge(({"red": 0}, {"blue": 1}, {"green": 2}), {"ordering": "fifo"})) + ("red", "blue", "green") + The map has fifo ordering, so the order of keys is predictable. + @@ -23079,15 +23185,15 @@ map:build($input, map:get(?, 'key'), map:get(?, 'value'), $combine) map as its $map argument. The $predicate function takes the key and the value of the corresponding map entry as an argument, and the result is a sequence containing the keys of those - entries for which the predicate function returns true in implementation-dependent order. + entries for which the predicate function returns true in + . A return value of () is treated as false.

-

The function is nondeterministic with respect to ordering + map:for-each($map, fn($key, $value) { @@ -23169,13 +23275,12 @@ return map:keys-where($birthdays, fn($name, $date) {

The function map:values takes any map as its $map argument and returns the values that are present in the map as - a sequence, in implementation-dependent order.

-

The function is nondeterministic with respect to ordering + a sequence, in .

+

The effect of the function is equivalent to $map?*.

@@ -23226,13 +23331,13 @@ return map:keys-where($birthdays, fn($name, $date) { >map
as its $map argument and returns the key-value pairs that are present in the map as a sequence of singleton maps, in implementation-dependent order.

+ def="dt-entry-order"/>.

-

The function is nondeterministic with respect to ordering + @@ -23242,12 +23347,19 @@ return map:keys-where($birthdays, fn($name, $date) { map:entries( - { 1: "yes", 2: "no" } + { 1: "yes", 0: "no" } ) - ({ 1: "yes" }, { 2: "no" }) + ({ 1: "yes" }, { 0: "no" }) The result sequence is in implementation-dependent order. + + map:entries( + { 1: "yes", 0: "no" } => map:sort(), +) + ({ 0: "no" }, { 1: "yes" }) + The result sequence is in key order. + @@ -23275,7 +23387,7 @@ return map:keys-where($birthdays, fn($name, $date) { >map as its $map argument and returns the keys that are present in the map as a sequence of key-value pair maps, in implementation-dependent order.

+ def="dt-entry-order"/>.

A key-value pair map is an instance of type record(key as xs:anyAtomicType, value as item()*): that is a map with two entries, one (with key "key") holding the key, and the other (with key "value") holding the value.

@@ -23533,9 +23645,7 @@ return (

To process an item that is a map, then for each key-value entry (K, V) - in the map (in implementation-dependent order) + in the map (in ) perform both of the following steps, in order:

@@ -23613,6 +23723,9 @@ declare function map:find($input as item()*, + +

Enhanced to allow for ordered maps.

+
@@ -23639,6 +23752,26 @@ declare function map:find($input as item()*, def="dt-same-key" >same key as $key, together with a new entry whose key is $key and whose associated value is $value.

+ +

The ordering property of the returned map is the same as the ordering + property of $map.

+ +

The of the entries in the returned map is as follows:

+ + +

If the ordering is random, then the is + , and has no necessary relationship with the + of $map.

+

If the ordering is sorted, then the is + sorted by key. A dynamic error occurs if the keys are not .

+ +

If the ordering is fifo then:

+ +

If the input $map contains an entry whose

+
+ +
+

The function supplied as $action takes two arguments. It is called supplying the key of the map entry as the first argument, and the associated value as the second argument.

@@ -23953,6 +24121,9 @@ return { depth="5"/>.

+ +

Enhanced to allow for ordered maps.

+
@@ -23981,6 +24152,11 @@ return {

The function supplied as $predicate takes two arguments. It is called supplying the key of the map entry as the first argument, and the associated value as the second argument.

+ +

The ordering property of the returned map is the same as the + ordering property of $map, and in the case of sorted + or fifo ordering the relative order of entries in the returned map + is the same as their relative order in $map.

map:for-each($map, fn($key, $value) { @@ -24008,6 +24184,16 @@ map:for-each($map, fn($key, $value) { ) { 1: "Sunday", 7: "Saturday" } + + map:filter( + { "Sunday": false(), "Monday": true(), "Tuesday": true(), "Wednesday": true(), + "Thursday": true(), "Friday": true(), "Saturday": false() } => map:sort(), + fn($k, $v) { $v } +) + { "Friday": true(), "Monday": true(), "Thursday": true(), + "Tuesday": true(), "Wednesday": true()} + The result is sorted because the input is sorted. + @@ -24017,6 +24203,7 @@ map:for-each($map, fn($key, $value) {

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

+

Enhanced to allow for ordered maps.

@@ -24043,14 +24230,36 @@ map:for-each($map, fn($key, $value) { the supplied $action to the existing value associated with that key.

Otherwise, the returned map contains an entry for the supplied $key whose value is obtained by applying the supplied $action to an empty sequence.

- - +

The ordering property of the returned map is the same as the ordering + property of $map.

+ +

The of the entries in the returned map is as follows:

+ + +

If the ordering is random, then the is + , and has no necessary relationship with the + of $map.

+

If the ordering is sorted, then the is + sorted by key. A dynamic error occurs if the keys are not .

+ +

If the ordering is fifo then:

+ +

If the input $map contains an entry whose

+
+ +
+
if (map:contains($map, $key)) then map:put($map, $key, $action(map:get($map, $key))) else map:put($map, $key, $action(())) + +

An error is raised if the option + ordering=sorted is requested, and the keys of the entries to be included in the result are not + .

+
@@ -24136,7 +24345,7 @@ else map:put($map, $key, $action(())) - + @@ -24155,11 +24364,57 @@ else map:put($map, $key, $action(())) Then, for each key value:

If the key is not already present in the target map, the processor adds a - new key-value pair to the map, with that key and that value.

-

If the key is already present, the processor calls the $combine - function to combine the existing value for the key with the new value, + new key-value pair to the map, with that key and that value.

+

If the key is already present, the processor calls the combine + function in the $options argument to combine the existing value for the key with the new value, and replaces the entry with this combined value.

+ +

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:

+ + + + 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 + . + + (fn(item()*, item()*) as item()*)? + fn:op(',') + + + Determines the ordering, and the , of the + entries in the returned map. + + enum("random", "sorted", "fifo") + random + + + The ordering property of the returned map is random, and its + is . + + + The ordering property of the returned map is sorted, and its + is sorted by key. A dynamic error occurs + if the keys are not . + + + The ordering property of the returned map is fifo, and its + reflects the order of the items supplied in $input, + and within each of those items, the order of the keys returned by the $keys function. + + + + + + + fold-left($input, {}, fn($map, $item, $pos) { @@ -24173,10 +24428,15 @@ fold-left($input, {}, fn($map, $item, $pos) { }) }) + +

An error is raised if the option + ordering=sorted is requested, and the keys of the entries to be included in the result are not + .

+
-

Although defined to process the input sequence in order, this is only relevant when combining the entries - for duplicate keys.

+

The default function for both $keys and $value is the identity function. Although it is permitted to default both, this serves little purpose: usually at least one of these arguments will be supplied.

@@ -24236,7 +24496,7 @@ fold-left($input, {}, fn($map, $item, $pos) { ("apple", "apricot", "banana", "blueberry", "cherry"), substring(?, 1, 1), string-length#1, - op("+") + { "combine": op("+") } ) { "a": 12, "b": 15, "c": 6 } Constructs a map where the key is the first character of an input item, and where the corresponding value @@ -24282,7 +24542,7 @@ return map:build($titles/title, fn($title) { $title/ix })

The following expression creates a map whose keys are employee @location values, and whose corresponding values represent the number of employees at each distinct location. Any employees that lack an @location attribute will be excluded from the result.

- map:build(//employee, fn { @location }, fn { 1 }, op("+")) + map:build(//employee, fn { @location }, fn { 1 }, { "combine": op("+") })

The following expression creates a map whose keys are employee @location values, and whose @@ -24340,6 +24600,136 @@ return map:build($titles/title, fn($title) { $title/ix }) + + + + + + + + + deterministic + context-independent + focus-independent + + +

Returns a sorted map with the same entries as a supplied map.

+ + +

The function map:sort takes any map + as its $map argument and returns a sorted map containing the + same entries.

+
+ + map:of-pairs(map:pairs($map), {'ordering': 'sorted'}) + + +

An error is raised if + the keys in $map are not + .

+
+ +

If the ordering property of $map is sorted, + then $map is returned unchanged.

+
+ + + + map:sort({ "a": 0, "z": 0, "q": 0 }) => map:keys() + "a", "q", "z" + + + map:sort({}) => map:put("x", 0) => map:put("a", 0) => map:keys() + "a", "x" + Adding entries to a sorted map, even if it is empty, produces a sorted map + + + + +

New in 4.0

+
+ + + + + + + + + + + + + + + deterministic + context-independent + focus-independent + + +

Returns a sorted map containing a subset of the entries of a supplied map.

+
+ +

The function filters the supplied $map to return those entries that are + within a given range of values.

+

The entries selected are those, up to a maximum count of $limit if specified, where the + key K satisfies all the following conditions:

+ + +

If $min-inclusive is supplied, then K is + greater than or equal to $min-inclusive

+

If $min-exclusive is supplied, then K is + greater than $min-exclusive

+

If $max-inclusive is supplied, then K is + less than or equal to $max-inclusive

+

If $max-exclusive is supplied, then K is + less than $max-exclusive

+
+
+ +let $CC := "http://www.w3.org/2005/xpath-functions/collation/codepoint" +return map:pairs(map:sort($map)) [ + (empty($min-inclusive) or compare(?key, $min-inclusive, $CC) ge 0) and + (empty($min-exclusive) or compare(?key, $min-exclusive, $CC) gt 0) and + (empty($max-inclusive) or compare(?key, $max-exclusive, $CC) le 0) and + (empty($max-inclusive) or compare(?key, $max-exclusive, $CC) le 0) +] => subsequence(1, $limit otherwise xs:double('+INF')) + => map:of-pairs({ "ordering": "sorted" }) + + +

An error is raised if + the keys in $map are not + .

+
+ +

The function is intended primarily to take advantage of efficiencies that + become possible when the supplied $map has ordering=sorted, + but it still works if the input is not sorted.

+

It would be unusual to supply both $min-inclusive and $min-exclusive, + or both $max-inclusive and $max-exclusive, but all combinations are permitted.

+
+ + + + map:sort({ "a": 1, "b": 2, "c": 3 }) => map:range(max-inclusive:="b") + { "a": 1, "b": 2 } + + + map:sort({ "a": 1, "b": 2, "c": 3 }) => map:range(min-inclusive:="b", max-exclusive="d") + { "b": 2, "c": 3 } + + + map:sort({ "aa": 1, "bb": 2, "cc": 3 }) => map:range(min-inclusive:="b", limit:=1) => map:keys() + "bb" + Returns the first key greater than or equal to the supplied value. + + + + +

New in 4.0

+
+
@@ -24794,6 +25184,19 @@ return $M(collation-key("a", $C)) + + + Determines whether the XML representation of a JSON object should retain the order + of entries in the input. + xs:boolean + true + + The children of any fn:map element in the output will be + in order. + The children of any fn:map element in the output will be + in the same order as the corresponding entries in the JSON input. + + Determines whether the generated XML tree is schema-validated. @@ -25304,7 +25707,8 @@ return json-to-xml($json, $options)]]> the children of the map element, enclosed between curly braces and separated by commas. Each entry comprises the value of the key attribute of the child element, enclosed in quotation marks and escaped as described below, followed by a colon, followed by the result of processing the child element - by applying these rules recursively.

+ by applying these rules recursively. The order of properties in the output JSON representation retains the order + of the children of the map element.

Comments, processing instructions, and whitespace text node children of map and array @@ -26733,6 +27137,19 @@ return { + + + Determines whether maps resulting from parsing of JSON objects should retain the input order. + xs:boolean + false + + Any maps resulting from parsing of JSON objects have the ordering + property set to random. + Any maps resulting from parsing of JSON objects have the ordering + property set to fifo, and the retains the order + of entries in the input. + + Determines whether special characters are represented in the XDM output in backslash-escaped form. @@ -26866,6 +27283,7 @@ return { { "x": 2, "y": 5 }.

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

+

The order of entries is retained if the retain-order option is set to true.

A JSON array is transformed to an array whose members are the result of converting diff --git a/specifications/xpath-functions-40/src/xpath-functions.xml b/specifications/xpath-functions-40/src/xpath-functions.xml index 73e77229c2..789ff4774f 100644 --- a/specifications/xpath-functions-40/src/xpath-functions.xml +++ b/specifications/xpath-functions-40/src/xpath-functions.xml @@ -7500,12 +7500,13 @@ return Maps +

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

-

A map is an additional kind of item.

+

A map is a kind of item.

-

A map consists of a set of entries, also known +

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.

@@ -7533,6 +7534,73 @@ return
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.

+ + Ordering of Maps + + + Ordered maps are introduced. + + +

A map has a property called its ordering, + which takes one of the values random, sorted, or fifo.

+ + +

Random is the default ordering, and was the only value available in + earlier versions of this specification. With random ordering, the order of entries in the + map is : with many implementations, it is likely + to be entirely unpredictable, based on some internal hashing function applied to the keys.

+ +

Sorted ordering maintains and delivers the entries in a map in ascending + order of the keys. This imposes a constraint that the keys must be .

+

A set of keys + is strictly comparable if for every pair of keys K1 + and K2, (a) the function fn:compare(K1, K2, $CC), + where $CC is the Unicode Codepoint Collation, can be evaluated without raising a type error, + and (b) if either K1 or K2 has a timezone component, then both have + a timezone component.

+

This disallows types such as xs:QName for which no ordering is defined, + and also disallows mixing of types such as xs:string and xs:integer + in the same map. The ordering chosen in context-independent, which means that strings + are always compared using the Unicode codepoint collation, and date/time values must either + all have a timezone, or all have no timezone.

+
+ +

Fifo (first-in, first-out) ordering maintains and delivers the + entries in a map in the order they were added: new entries are added at the end. The detailed + rules are determined by the map:put function.

+
+ +

A sorted map may be constructed using the map:sort function. Adding or removing + entries to a sorted map will maintain the sort order. In some cases it is convenient to + construct an empty map with the property ordering=sorted using the + expression map:sort({}), and then build the map by adding entries incrementally. + Alternatively, a sorted map may be constructed by calling any of the functions + map:build, map:merge, or map:of-pairs with + the option ordering=sorted.

+ +

A map with ordering fifo may be constructed by calling any of the functions + map:build, map:merge, or map:of-pairs with + the option ordering=fifo. These functions may be used to construct an empty + map with this ordering property, to which entries can then be added incrementally; or they + may be used to construct a map in which the order of entries reflect the order of items + in the sequence supplied as input.

+ +

Maps with ordering fifo are also constructed by certain operations such + as parse-json and xml-to-json.

+ +

The order of entries in a map + (which is dependent on its ordering + property) is referred to as entry order.

+

The of the entries in a map is + respected by functions such as map:entries, + map:keys, map:values, map:pairs, map:for-each, and + json-to-xml. It also affects the result of the expression + for key $k value $v return EXPR, and the output + of the json and adaptive serialization methods.

+ + +
+ Composing and Decomposing Maps @@ -7609,7 +7677,7 @@ return
Formal Specification of Maps

The XDM data model () defines three primitive operations on maps:

-

dm:empty-map constructs an empty map.

+

dm:empty-map constructs an empty map with a given ordering property.

dm:map-put adds or replaces an entry in a map.

dm:iterate-map applies a supplied function to every entry in a map.

@@ -12700,6 +12768,12 @@ ISBN 0 521 77752 6. or key contains an invalid JSON escape sequence.

+ +

Raised by various functions if an attempt is made to construct a map with the ordering + property set to sorted when the keys to be included in the map + are not .

+
+ diff --git a/specifications/xquery-40/src/expressions.xml b/specifications/xquery-40/src/expressions.xml index 64c0141948..4b98a2ef46 100644 --- a/specifications/xquery-40/src/expressions.xml +++ b/specifications/xquery-40/src/expressions.xml @@ -16883,7 +16883,7 @@ let $z := g($x, $y)]]>

When a ForEntryBinding is used (that is, when either or both of the keywords key and value are used), the key range variable (if present) is bound in turn to each key in the map - (in order), and the value + (in entry order), and the value range variable (if present) is bound to the corresponding value.

In this case the corresponding ExprSingle must evaluate to a single map, otherwise a type error is raised

+ +

The ordering property of a map constructed using a map constructor expression + is random.

+ + +

A map with sorted ordering can be created by applying the map:sort + function.

+

A map with fifo ordering can be created by use of the functions map:build, + map:merge, or map:of-pairs with the option { "ordering": "fifo" }.

+
Constructing a fixed map @@ -19891,6 +19901,9 @@ processing with JSON processing.

the result is the same as $V?pairs::(map:keys($V)).

The order of entries in the result sequence in this case + reflects the entry order + of the map. In the default case where the ordering of the + map is random, the order of entries in the result sequence is implementation-dependent.

@@ -20515,7 +20528,12 @@ return $array?[count(.) ge 2] The context position is the position of the entry in the map (in an arbitrary ordering), and the context size is the number of entries in the map. The result of the expression is a map containing those entries of the input map for which - the of the FILTER expression is true.

+ the of the FILTER expression is true. + The ordering property of the result is the same as the ordering + property of the input map, and in the case of sorted or fifo + ordering the relative order of entries in the result retains the relative order of entries + in the input. +

For example, the following expression:

@@ -20527,8 +20545,10 @@ return $map?[?key ge 2] { 2: "beta", 3: "gamma" } -

Filtering of maps based on numeric positions is not generally useful, because the order of entries - in a map is unpredictable; but it is available in the interests of orthogonality.

+

Filtering of maps based on numeric positions is not generally useful when + the ordering of the map is random, + because the order of entries in a map is unpredictable; but it is available + in the interests of orthogonality.

diff --git a/specifications/xslt-40/src/element-catalog.xml b/specifications/xslt-40/src/element-catalog.xml index e2f00aabee..0cdd8b54e1 100644 --- a/specifications/xslt-40/src/element-catalog.xml +++ b/specifications/xslt-40/src/element-catalog.xml @@ -1662,6 +1662,13 @@ + + + + + + + diff --git a/specifications/xslt-40/src/xslt.xml b/specifications/xslt-40/src/xslt.xml index 63447a7f52..5869dc3676 100644 --- a/specifications/xslt-40/src/xslt.xml +++ b/specifications/xslt-40/src/xslt.xml @@ -35455,6 +35455,13 @@ the same group, and the--> the union of the map entries from the supplied sequence of maps.

+

If the ordering attribute is present then its is used + as the value of the ordering option in the call to map:merge.

+ + +

The effect of the three different map ordering options is explained in .

+
+

The handling of duplicate keys is described in below.

diff --git a/specifications/xslt-xquery-serialization-40/src/xslt-xquery-serialization.xml b/specifications/xslt-xquery-serialization-40/src/xslt-xquery-serialization.xml index 80429956c6..bc12d5fffe 100644 --- a/specifications/xslt-xquery-serialization-40/src/xslt-xquery-serialization.xml +++ b/specifications/xslt-xquery-serialization-40/src/xslt-xquery-serialization.xml @@ -3451,13 +3451,16 @@ the string value of the key the serialized JSON value of the entry, separated by delimiters according to the JSON object syntax, i.e. {key:value, key:value, ...}. -The order in which each key/value pair appears -in the serialized output is -implementation-dependent.

-When map items are serialized using the JSON +The key/value pairs in the serialized output retain the + entry order of entries in the map.

+ +

The order is implementation-dependent in + the default case where the ordering + property of the map is random.

+

If any two keys of the map item have the same string value, serialization error is raised, @@ -3851,9 +3854,16 @@ to output parentheses around a singleton if this avoids buffering data in memory A map item is serialized using the syntax of a without the optional map keyword, that is in the format {key:value, key:value, ...}. -The order of entries is implementation-dependent. The key is serialized by applying the rules +The key/value pairs in the serialized output retain the + entry order of entries in the map. + The key is serialized by applying the rules for serializing an atomic item. The values are serialized in the same way as the members of an array (see above). -

+

+ +

The order of entries is implementation-dependent in + the default case where the ordering + property of the map is random.

+

A function item is serialized to the representation name#A where