diff --git a/specifications/xpath-functions-40/src/function-catalog.xml b/specifications/xpath-functions-40/src/function-catalog.xml index 84b63f9c1..deb7b73f9 100644 --- a/specifications/xpath-functions-40/src/function-catalog.xml +++ b/specifications/xpath-functions-40/src/function-catalog.xml @@ -23025,8 +23025,8 @@ xs:QName('xs:double')

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.

+ >same key, then the entries are combined into a single entry as + controlled by the second ($options) argument.

@@ -23044,6 +23044,24 @@ xs:QName('xs:double') def="option-parameter-conventions" >option parameter conventions apply.

+ +

In the event that two or more entries in the input maps have the + :

+ +

A single entry is created by combining the duplicates.

+

The value of the resulting entry is formed by combining + the entries in the input maps according to the value of the + duplicates option.

+

The key of the resulting entry is one of the keys from + the duplicate entries: which one is chosen is . + (Two keys that are deemed duplicates may differ: for example they may have + different type annotations, or they may be xs:dateTime + values with different timezones.)

+

The position of the combined entry in the + of the result map corresponds to the position of the first appearance of + the corresponding key value in the input.

+
+

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

@@ -23088,14 +23106,7 @@ xs:QName('xs:double') If duplicate keys are present, the result map includes an entry for the key whose associated value is the sequence concatenation - 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). + of all the values associated with the key. @@ -23104,6 +23115,8 @@ xs:QName('xs:double')
+ + @@ -23116,16 +23129,8 @@ let $duplicates-handler := { "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")) -) +return map:of-pairs($maps =!> map:pairs(), + $duplicates-handler?($options?duplicates otherwise 'use-first')) @@ -23140,24 +23145,22 @@ return fold-left($maps, {}, -

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.

- +

By way of explanation, the function first reduces the sequence of input maps + to a sequence of key-value pairs, retaining order of both the maps and of the + entries within each map. It then combines key-value pairs having the + by applying the $combine function + successively to pairs of duplicates. The position in the + of the result map of an entry formed by combining duplicates corresponds to the + position of the first occurrence of the key in the input sequence. This is true + even whien the option use-last is used: the value of the resulting + entry corresponds to the last entry with a given key, but the position of the entry + in the result map corresponds to the position of the first entry with that key. +

-

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.

+ implementation and is not intended to be a realistic implementation.

@@ -23269,7 +23272,14 @@ return fold-left($maps, {},

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.

+ of the corresponding values, retaining the order in which they appear + in the input sequence; the position of the combined entry in the + of the result map corresponds + to the position of the first occurrence of the key value in $input. + Given that two keys deemed to be duplicates might differ (for example, they + might have different type annotations, or they might be xs:dateTime + values with different timezones), it is + which of the key values is used in the combined entry.

@@ -24522,10 +24532,21 @@ 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.

+ new key-value pair to the map, with that key and that value. The new entry + appears after all existing entries in the + of the result map.

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

+ and replaces the existing entry with this combined value, in its existing + position. The effect is that in the presence of duplicate keys, the order + of entries in the result map reflects the order of first appearance + of a key in the $input sequence. +

+

Given that two keys deemed to be duplicates might differ (for example, they + might have different type annotations, or they might be xs:dateTime + values with different timezones), it is + which of the key values is used in the combined entry. +

diff --git a/specifications/xslt-40/src/xslt.xml b/specifications/xslt-40/src/xslt.xml index e939395b8..cce444dbb 100644 --- a/specifications/xslt-40/src/xslt.xml +++ b/specifications/xslt-40/src/xslt.xml @@ -35797,7 +35797,12 @@ the same group, and the--> arguments to this function, and the function returns the value that should be associated with this key in the final map.

-

The order of the arguments passed to the function reflects the order of the maps in which +

More specifically, if the on-duplicates expression is present and returns + a function $F, and if the input sequence is $S, then the result of the + xsl:map instruction is equivalent to the result of the function call + map:of-pairs($S =!> map:pairs(), { 'combine': $F }).

+ +

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, and explains their effect:

@@ -35870,6 +35875,19 @@ the same group, and the--> + +

The position in the result map of the combined entry + corresponding to a set of duplicate + entries in the input corresponds to the position of the first of the duplicates + in the input.

+

The key of the combined entry corresponding to a set of duplicate + entries in the input is one of the duplicate keys, but it is + which one is chosen. (Two keys + can be duplicates even if they differ: for example, they may have different + type annotations, or two xs:dateTime values might have different + timezones.)

+
+ Combining Duplicates into an Array

This example takes as input an XML document such as: