From 39fa65ba5377cc9947b04988151c4e882375e74d Mon Sep 17 00:00:00 2001 From: Michael Kay Date: Tue, 4 Feb 2025 00:22:21 +0000 Subject: [PATCH] map:put may use either the new or the old key --- .../src/function-catalog.xml | 57 ++++++++------- .../src/xpath-functions.xml | 6 ++ .../xslt-40/src/element-catalog.xml | 2 +- .../xslt-40/src/schema-for-xslt40.rnc | 5 +- .../xslt-40/src/schema-for-xslt40.xsd | 8 +-- specifications/xslt-40/src/xslt.xml | 71 +++++++++++-------- 6 files changed, 84 insertions(+), 65 deletions(-) diff --git a/specifications/xpath-functions-40/src/function-catalog.xml b/specifications/xpath-functions-40/src/function-catalog.xml index 67718b729..8ec830394 100644 --- a/specifications/xpath-functions-40/src/function-catalog.xml +++ b/specifications/xpath-functions-40/src/function-catalog.xml @@ -23048,8 +23048,9 @@ xs:QName('xs:double')

The position of that entry in the of the result map will correspond to the position of the first of the duplicates.

-

The key of that entry will be the key used - in the last of the duplicates. (Keys may be +

The key of the combined entry + will correspond to the key of one of the duplicates: it is + which one is chosen. (Keys may be duplicates even though they differ: for example, they may have different type annotations, or they may be xs:dateTime values in different timezones.)

@@ -23062,7 +23063,7 @@ xs:QName('xs:double') map:of-pairs($maps =!> map:pairs(), - $options[exists((?duplicates, ?combine))] + $options[exists(?duplicates)] otherwise { "duplicates": "use-first" }); @@ -23214,7 +23215,7 @@ map:of-pairs($maps =!> map:pairs(),

The function map:of-pairs - returns a map that + returns a map which is formed by combining key-value pair maps supplied in the $input argument.

@@ -23343,8 +23344,10 @@ return fold-left( $input, {}, of the result map, the position of the entry containing the result of combining a set of entries with duplicate keys corresponds to the position of the first of the duplicates in the input sequence.

-

The key of the entry containing the combined value is the last of - the several duplicates. (Keys may be duplicates even though they differ: +

The key of the combined entry + will correspond to the key of one of the duplicates: it is + which one is chosen. + (Keys may be duplicates even though they differ: for example they may have different type annotations, or they might be xs:dateTime values in different timezones.)

@@ -24120,20 +24123,18 @@ declare function map:find($input as item()*, any existing entry for the same key.

-

The function map:put returns a map that contains all entries from the supplied $map, - with the exception of any entry whose key is the same key as $key, together with a new - entry whose key is $key and whose associated value is $value.

+

If $map contains an entry whose key is the same key as $key, the function returns + a map in which that entry is replaced (at the same relative position) + with a new entry whose value is $value. It is + whether the key in the new entry + takes its original value or is replaced by the supplied $key. + All other entries in the map are unchanged, and retain their relative order.

-

The entry order - of the entries in the returned map is as follows: - if $map contains an entry whose key is $key, - then the new value replaces the old value and the position of the entry is not changed; - otherwise, the new entry is added after all existing entries.

- - +

Otherwise, when $map contains no such entry, the function + returns a map containing all entries from the supplied $map + (retaining their relative position) followed by a new entry whose key + is $key and whose associated value is $value.

@@ -24154,8 +24155,9 @@ declare function map:find($input as item()*, as some existing key present in $map, but nevertheless differs from the existing key in some way: for example, it might have a different type annotation, or it might be an xs:dateTime - value in a different timezone. In this situation the key that appears in the result map - is always the supplied $key, not the existing key.

+ value in a different timezone. In this situation it is + whether the key that appears in the result map + is the supplied $key or the existing key.

@@ -24191,7 +24193,12 @@ declare function map:find($input as item()*, -

Enhanced to allow for ordered maps.

+ +

Enhanced to allow for ordered maps.

+
+ +

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

+
@@ -24639,9 +24646,9 @@ else map:put($map, $key, $action(()))

The position of the combined entry in the of the result map will correspond to the position of the first of the duplicates.

-

The key of the combined entry in the - of the result map - will correspond to the key of the last of the duplicates. +

The key of the combined entry + will correspond to the key of one of the duplicates: it is + which one is chosen. (It is possible for two keys to be considered duplicates even if they differ: for example, they may have different type annotations, or they may be xs:dateTime values in different timezones.)

diff --git a/specifications/xpath-functions-40/src/xpath-functions.xml b/specifications/xpath-functions-40/src/xpath-functions.xml index f89045079..c6a7eb042 100644 --- a/specifications/xpath-functions-40/src/xpath-functions.xml +++ b/specifications/xpath-functions-40/src/xpath-functions.xml @@ -13816,6 +13816,12 @@ ISBN 0 521 77752 6. 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.

+ +

When fn: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.

+

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

diff --git a/specifications/xslt-40/src/element-catalog.xml b/specifications/xslt-40/src/element-catalog.xml index 96973de4a..6b87e08a6 100644 --- a/specifications/xslt-40/src/element-catalog.xml +++ b/specifications/xslt-40/src/element-catalog.xml @@ -1702,7 +1702,7 @@ - + - A new attribute xsl:map/@on-duplicates is available, + A new attribute xsl:map/@duplicates is available, allowing control over how duplicate keys are handled by the xsl:map instruction. @@ -36139,25 +36139,26 @@ the same group, and the--> and fn:atomic-equal(K, L) returns true.

-

In the absence of the on-duplicates attribute, +

In the absence of the duplicates attribute, a dynamic error occurs if the set of keys in the maps making up the input sequence of an xsl:map instruction contains duplicates.

-

The result of evaluating the on-duplicates attribute, if present, must - be a function with arity 2. When the xsl:map instruction encounters two - map entries having the same key, the two values associated with this key are passed as - arguments to this function, and the function returns the value that should be associated - with this key in the final map.

- -

More formally, the result of the xsl:map instruction is defined by reference to - the function map:merge. Specifically, if $maps - is the input sequence to xsl:map, and $combine - is the of the on-duplicates +

The result of evaluating the duplicates attribute, if present, must + be either one of the strings "use-first", "use-last", + "use-any", "combine", or "reject", + or a function with arity 2. These values correspond to the permitted + values of the duplicates option of the + map:of-pairs function.

+ +

The result of the xsl:map instruction is defined by reference to + the function map:of-pairs. Specifically, if $maps + is the input sequence to xsl:map, and $duplicates + is the of the duplicates attribute, then the result of the instruction is the result of the function - call map:merge($maps, { "combine": $combine }).

+ call map:of-pairs(map:pairs($maps), { "duplicates": $duplicates }).

Thus, if the values are all singleton items (which is not necessarily the case), and if the sequence of values is S, then the final result is fold-left(tail(S), head(S), F).

--> -

For example, the following table shows some useful callback functions that might be supplied - as the value of the on-duplicates attribute, and explains their effect:

+

The following table shows some possible values + of the duplicates attribute, and explains their effect:

@@ -36195,41 +36196,47 @@ the same group, and the--> - + - + - + - + - + - + - - - + + + + + + - - + +
fn($a, $b) { $a }duplicates="use-first" The first of the duplicate values is used.
fn($a, $b) { $b }duplicates="use-last" The last of the duplicate values is used.
fn($a, $b) { $a, $b }duplicates="combine" The of the duplicate values is used. This could also be expressed as on-duplicates="op(',')".
fn($a, $b) { max(($a, $b)) }duplicates="fn($a, $b) { max(($a, $b)) }" The highest of the duplicate values is used.
fn($a, $b) { min(($a, $b)) }duplicates="fn($a, $b) { min(($a, $b)) }" The lowest of the duplicate values is used.
concat(?, ', ', ?) }duplicates="concat(?, ', ', ?) }" The comma-separated string concatenation of the duplicate values is used.
fn($a, $b) { $a + $b }The sum of the duplicate values is used. - This could also be expressed as on-duplicates="op('+')" +
duplicates="op('+')"The sum of the duplicate values is used.
duplicates="fn($a, $b) { subsequence(($a, $b), 1, 4) }"The first four of the duplicates are retained; any further duplicates + are discarded.
fn($a, $b) { error() }Duplicates are rejected as an error (this is the default in the absence of the - on-duplicates attribute).duplicates="fn($a, $b) { distinct-values(($a, $b)) }"When multiple entries have the same key, the corresponding values + are retained only if they are distinct from other values having the + same key. +
@@ -36247,7 +36254,7 @@ the same group, and the-->

The logic is:

- + @@ -36256,14 +36263,16 @@ the same group, and the--> -

Specifying the effect by reference to map:merge has +

Specifying the effect by reference to map:of-pairs has the following consequences when duplicates are combined into a merged entry:

The position of the merged entry in the result corresponds to the position of the first of the duplicate keys in the input.

The key used for the merged entry in the result corresponds - to the last of the duplicate keys in the input. This is relevant when + to one of the duplicate keys in the input: it is + which one is chosen. + This is relevant when the duplicate keys differ in some way, for example when they have different type annotations, or when they are xs:dateTime values in different timezones.