@@ -36126,7 +36126,7 @@ the same group, and the-->
36126
36126
36127
36127
<changes>
36128
36128
<change issue="169" date="2023-11-28">
36129
- A new attribute <code>xsl:map/@on- duplicates</code> is available,
36129
+ A new attribute <code>xsl:map/@duplicates</code> is available,
36130
36130
allowing control over how duplicate keys are handled by the <elcode>xsl:map</elcode>
36131
36131
instruction.
36132
36132
</change>
@@ -36138,25 +36138,26 @@ the same group, and the-->
36138
36138
and <code>fn:atomic-equal(<var>K</var>, <var>L</var>)</code> returns <code>true</code>.</p>
36139
36139
36140
36140
<p><error spec="XT" class="DE" code="3365" type="dynamic">
36141
- <p>In the absence of the <code>on- duplicates</code> attribute,
36141
+ <p>In the absence of the <code>duplicates</code> attribute,
36142
36142
a <termref def="dt-dynamic-error">dynamic error</termref> occurs if the set of
36143
36143
keys in the maps making up the input sequence
36144
36144
<error.extra>of an <elcode>xsl:map</elcode> instruction</error.extra>
36145
36145
contains duplicates.</p>
36146
36146
</error></p>
36147
36147
36148
- <p>The result of evaluating the <code>on-duplicates</code> attribute, if present, <rfc2119>must</rfc2119>
36149
- be a function with arity 2. When the <elcode>xsl:map</elcode> instruction encounters two
36150
- map entries having the same key, the two values associated with this key are passed as
36151
- arguments to this function, and the function returns the value that should be associated
36152
- with this key in the final map.</p>
36153
-
36154
- <p>More formally, the result of the <elcode>xsl:map</elcode> instruction is defined by reference to
36155
- the function <xfunction>map:merge</xfunction>. Specifically, if <code>$maps</code>
36156
- is the input sequence to <elcode>xsl:map</elcode>, and <code>$combine</code>
36157
- is the <termref def="dt-effective-value"/> of the <code>on-duplicates</code>
36148
+ <p>The result of evaluating the <code>duplicates</code> attribute, if present, <rfc2119>must</rfc2119>
36149
+ be either one of the strings <code>"use-first"</code>, <code>"use-last"</code>,
36150
+ <code>"use-any"</code>, <code>"combine"</code>, or <code>"reject"</code>,
36151
+ or a function with arity 2. These values correspond to the permitted
36152
+ values of the <code>duplicates</code> option of the
36153
+ <xfunction>map:of-pairs</xfunction> function.</p>
36154
+
36155
+ <p>The result of the <elcode>xsl:map</elcode> instruction is defined by reference to
36156
+ the function <xfunction>map:of-pairs</xfunction>. Specifically, if <code>$maps</code>
36157
+ is the input sequence to <elcode>xsl:map</elcode>, and <code>$duplicates</code>
36158
+ is the <termref def="dt-effective-value"/> of the <code>duplicates</code>
36158
36159
attribute, then the result of the instruction is the result of the function
36159
- call <code>map:merge( $maps, { "combine ": $combine })</code>.</p>
36160
+ call <code>map:of-pairs(map:pairs( $maps) , { "duplicates ": $duplicates })</code>.</p>
36160
36161
36161
36162
<!--
36162
36163
@@ -36182,8 +36183,8 @@ the same group, and the-->
36182
36183
<p>Thus, if the values are all singleton items (which is not necessarily the case), and if the sequence
36183
36184
of values is <var>S</var>, then the final result is <code>fold-left(tail(S), head(S), F)</code>.</p>
36184
36185
-->
36185
- <p>For example, the following table shows some useful callback functions that might be supplied
36186
- as the value of the <code>on- duplicates</code> attribute, and explains their effect:</p>
36186
+ <p>The following table shows some possible values
36187
+ of the <code>duplicates</code> attribute, and explains their effect:</p>
36187
36188
36188
36189
<table>
36189
36190
<thead>
@@ -36194,41 +36195,47 @@ the same group, and the-->
36194
36195
</thead>
36195
36196
<tbody>
36196
36197
<tr>
36197
- <td><code>fn($a, $b) { $a } </code></td>
36198
+ <td><code>duplicates="use-first" </code></td>
36198
36199
<td>The first of the duplicate values is used.</td>
36199
36200
</tr>
36200
36201
<tr>
36201
- <td><code>fn($a, $b) { $b } </code></td>
36202
+ <td><code>duplicates="use-last" </code></td>
36202
36203
<td>The last of the duplicate values is used.</td>
36203
36204
</tr>
36204
36205
<tr>
36205
- <td><code>fn($a, $b) { $a, $b } </code></td>
36206
+ <td><code>duplicates="combine" </code></td>
36206
36207
<td>The <xtermref spec="XP40" ref="dt-sequence-concatenation"/>
36207
36208
of the duplicate values is used. This could
36208
36209
also be expressed as <code>on-duplicates="op(',')"</code>.</td>
36209
36210
</tr>
36210
36211
<tr>
36211
- <td><code>fn($a, $b) { max(($a, $b)) }</code></td>
36212
+ <td><code>duplicates=" fn($a, $b) { max(($a, $b)) }" </code></td>
36212
36213
<td>The highest of the duplicate values is used.</td>
36213
36214
</tr>
36214
36215
<tr>
36215
- <td><code>fn($a, $b) { min(($a, $b)) }</code></td>
36216
+ <td><code>duplicates=" fn($a, $b) { min(($a, $b)) }" </code></td>
36216
36217
<td>The lowest of the duplicate values is used.</td>
36217
36218
</tr>
36218
36219
<tr>
36219
- <td><code>concat(?, ', ', ?) }</code></td>
36220
+ <td><code>duplicates=" concat(?, ', ', ?) }" </code></td>
36220
36221
<td>The comma-separated string concatenation of the duplicate values is used.</td>
36221
36222
</tr>
36222
- <tr diff="add" at="2023-04-04">
36223
- <td><code>fn($a, $b) { $a + $b }</code></td>
36224
- <td>The sum of the duplicate values is used.
36225
- This could also be expressed as <code>on-duplicates="op('+')"</code>
36223
+ <tr>
36224
+ <td><code>duplicates="op('+')"</code></td>
36225
+ <td>The sum of the duplicate values is used.</td>
36226
+ </tr>
36227
+ <tr>
36228
+ <td><code>duplicates="fn($a, $b) { subsequence(($a, $b), 1, 4) }"</code></td>
36229
+ <td>The first four of the duplicates are retained; any further duplicates
36230
+ are discarded.
36226
36231
</td>
36227
36232
</tr>
36228
36233
<tr>
36229
- <td><code>fn($a, $b) { error() }</code></td>
36230
- <td>Duplicates are rejected as an error (this is the default in the absence of the
36231
- <code>on-duplicates</code> attribute).</td>
36234
+ <td><code>duplicates="fn($a, $b) { distinct-values(($a, $b)) }"</code></td>
36235
+ <td>When multiple entries have the same key, the corresponding values
36236
+ are retained only if they are distinct from other values having the
36237
+ same key.
36238
+ </td>
36232
36239
</tr>
36233
36240
</tbody>
36234
36241
</table>
@@ -36246,7 +36253,7 @@ the same group, and the-->
36246
36253
<eg><![CDATA[{ "A23": [ 12, 2 ], "A24": [ 5 ], "A23": [ 9 ] }]]></eg>
36247
36254
<p>The logic is:</p>
36248
36255
<eg><![CDATA[<xsl:template match="data">
36249
- <xsl:map on- duplicates="fn($a, $b) { array:join(($a, $b)) }">
36256
+ <xsl:map duplicates="fn($a, $b) { array:join(($a, $b)) }">
36250
36257
<xsl:for-each select="event">
36251
36258
<xsl:map-entry key="@id" select="[xs:integer(@value)]"/>
36252
36259
</xsl:for-each>
@@ -36255,14 +36262,16 @@ the same group, and the-->
36255
36262
</example>
36256
36263
36257
36264
<note>
36258
- <p>Specifying the effect by reference to <xfunction>map:merge </xfunction> has
36265
+ <p>Specifying the effect by reference to <xfunction>map:of-pairs </xfunction> has
36259
36266
the following consequences when duplicates are combined
36260
36267
into a merged entry:</p>
36261
36268
<ulist>
36262
36269
<item><p>The position of the merged entry in the result corresponds
36263
36270
to the position of the first of the duplicate keys in the input.</p></item>
36264
36271
<item><p>The key used for the merged entry in the result corresponds
36265
- to the last of the duplicate keys in the input. This is relevant when
36272
+ to one of the duplicate keys in the input: it is
36273
+ <termref def="dt-implementation-dependent"/> which one is chosen.
36274
+ This is relevant when
36266
36275
the duplicate keys differ in some way, for example when they have
36267
36276
different type annotations, or when they are <code>xs:dateTime</code>
36268
36277
values in different timezones.</p></item>
0 commit comments