From cb24d3fdfec2c9737673741932a714842fb7de84 Mon Sep 17 00:00:00 2001 From: Michael Kay Date: Fri, 29 Nov 2024 13:02:44 +0000 Subject: [PATCH] Specify keys-as-maps function --- .../xslt-40/src/function-catalog.xml | 221 ++++++++++++++---- specifications/xslt-40/src/xslt.xml | 43 +++- 2 files changed, 209 insertions(+), 55 deletions(-) diff --git a/specifications/xslt-40/src/function-catalog.xml b/specifications/xslt-40/src/function-catalog.xml index ac34d71112..57965675f1 100644 --- a/specifications/xslt-40/src/function-catalog.xml +++ b/specifications/xslt-40/src/function-catalog.xml @@ -1164,7 +1164,8 @@

Returns the nodes that match a supplied key value.

-

The key function does for keys what the element-with-id function does for IDs.

+

The key function provides access to the nodes in a document that + have a specified key value.

The $key-name argument specifies the name of the key. The value of the argument must be either an xs:QName, or a string containing an . If it is @@ -1185,11 +1186,10 @@ the function is a sequence of nodes, in document order and with duplicates removed, comprising those nodes in the selected subtree (see below) that are matched by an xsl:key declaration whose name is the same as the - supplied key name, where the result of evaluating the key specifier contains a value that is equal - to one of these requested key values, under the rules appropriate to the XPath - eq operator for the two values in question, using the - collation attributes of the xsl:key declaration - when comparing strings. No error is reported if two values are encountered that + supplied key name, where the result of evaluating the + key specifier contains a value that is equal + to one of these requested key values: the rules for comparing two items + are given below. No error is reported if two values are encountered that are not comparable; they are regarded for the purposes of this function as being not equal.

If the second argument is an empty sequence, the result of the function will be an @@ -1204,44 +1204,42 @@ (see below) that are matched by an xsl:key declaration whose name is the same as the supplied key name, where the result of evaluating the key specifier is deep-equal to the requested key value, under the rules appropriate to the deep-equal - function applied to the two values in question, using the collation - attributes of the xsl:key declaration when comparing strings. - Note that the deep-equal function reports no error if two - values are encountered that are not comparable; they are regarded for the purposes - of this function as being not equal.

+ function applied to the two values in question: the detailed comparison rules are + defined below.

If the second argument is an empty sequence, the result of the function will be the set of nodes having an empty sequence as the value of the key specifier.

- - -

Different rules apply when XSLT 1.0 compatible behavior is enabled.

- -

A key (that is, a set of xsl:key - declarations sharing the same key name) is processed in backwards compatible mode if (a) - at least one of the xsl:key elements in the definition of the key enables backwards - compatible behavior, and (b) the effective value of the composite attribute - is no.

- -

When a key is processed in backwards compatible mode, - then:

- - - - -

The result of evaluating the key specifier in any xsl:key - declaration having this key name is converted after atomization to a sequence of - strings, by applying a cast to each item in the sequence.

-
- - -

When the first argument to the key function specifies this key - name, then the value of the second argument is converted after atomization to a - sequence of strings, by applying a cast to each item in the sequence. The values are - then compared as strings.

-
-
+ +

Two atomic items K1 and K2 are deemed equal if they satisfy + one of the following rules:

+ + +

If both K1 and K2 are of type + xs:string, xs:untypedAtomic, + or xs:anyURI, then compare(K1, K2, $collation) + returns zero, where $collation is the collation of the key definition.

+

Otherwise, atomic-equal(K1, K2) + returns true.

+
+ +

When the composite option is true, then two sequences of atomic + items S1 and S2 are deemed equal if deep-equal(S1, + S2, {'items-equal': $F})) returns true, where $F is the function + just described for comparing atomic items.

+ + +

The rules for comparing items have changed in this version of the specification, + in the interests of bringing keys into line with maps. The main differences are:

+ +

Numeric equality is transitive. In particular, when comparing an xs:double + value to an xs:decimal, they must now be exactly numerically equal; the xs:decimal + was previously converted to the nearest xs:double.

+

The implicit timezone is no longer used when comparing date/time values with a timezone + to values without one. To be equal, the values must either both have a timezone, or both be without one.

+
+

The third argument is used to identify the selected subtree. If the argument is present, @@ -1271,20 +1269,47 @@ xsl:key declaration is evaluated with a singleton focus based on $N, the atomized value of the resulting sequence includes a value that compares equal to at least one item in the atomized - value of the sequence supplied as $key-value, under the rules of the - eq operator with the collation selected as described above.

+ value of the sequence supplied as $key-value, using the equality + comparison defined above.

+

When composite="yes", and the key specifier of that xsl:key declaration is evaluated with a singleton focus based on $N, the atomized value of the resulting sequence compares equal to the atomized value of the sequence supplied as $key-value, under the rules of the - deep-equal function with the collation selected as - described above.

+ deep-equal function as described above.

The sequence returned by the key function will be in document order, with duplicates (that is, nodes having the same identity) removed.

+ +

Different rules apply when XSLT 1.0 compatible behavior is enabled.

+ +

A key (that is, a set of xsl:key + declarations sharing the same key name) is processed in backwards compatible mode if (a) + at least one of the xsl:key elements in the definition of the key enables backwards + compatible behavior, and (b) the effective value of the composite attribute + is no.

+ +

When a key is processed in backwards compatible mode, + then:

+ + + + +

The result of evaluating the key specifier in any xsl:key + declaration having this key name is converted after atomization to a sequence of + strings, by applying a cast to each item in the sequence.

+
+ + +

When the first argument to the key function specifies this key + name, then the value of the second argument is converted after atomization to a + sequence of strings, by applying a cast to each item in the sequence. The values are + then compared as strings.

+
+

@@ -1419,8 +1444,118 @@ + + +

The rules for equality comparison have changed to bring keys into line with maps.

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

Delivers the content of a key, for a specific document or subtree, as a map.

+
+ +

The effect of the function is to return a map $M such that + map:get($M, $key) returns the same result as key($key-name, $key, $top).

+

The function is defined only for maps that satisfy the following constraints:

+ +

The key's collation must be the Unicode Codepoint Collation.

+

The key must not specify composite=yes.

+
+ +

The $key-name argument specifies the name of the key. + The value of the argument must be either an xs:QName, or + a string containing an . If it is + a lexical QName, then it is expanded as + described in (no prefix means no namespace).

+ +

The $top argument is used to identify the selected subtree. If the argument is present, + the selected subtree is the set of nodes that have $top as an + ancestor-or-self node. If the argument is omitted, the selected subtree is the document + containing the context node. This means that the third argument effectively defaults to + /.

+ +

The returned map contains one entry (K, V) for every atomic item K + where the result of key($key-name, K, $top) is not empty, with V + set to the result of key($key-name, K, $top).

+
+ +

It is a dynamic error if the value + of the first argument to the map-for-key + function is not a valid QName, or if there is no namespace + declaration in scope for the prefix of the QName, or if the name obtained by + expanding the QName is not the same as the expanded name of any + xsl:key declaration in the containing package. If the + processor is able to detect the error statically (for example, when the argument + is supplied as a string literal), then the processor may + optionally raise this as a static + error . +

+

+ +

It is a dynamic + error if the key identified in a call to the function map-for-key + is unsuitable because it uses a collation other than the Unicode Codepoint Collation, or because + it is defined with composite=yes.

+ +

+

+ It is a dynamic + error to call the key function with + two arguments if there is no context + node, or if the root of the tree containing the context node is not a + document node; or to call the function with three arguments if the root of the + tree containing the node supplied in the third argument is not a document + node . +

+
+ +

The function has two main uses:

+ +

It enables the key values present in a key to be enumerated.

+

It enables the keys for multiple documents to be combined into a single map, for example + by using map:merge.

+
+
+ + + + Finding keys that are present in one document but absent in another +

This example uses a key identifying employees in an employee file by their social security + number.

+

The key might be defined like this:

+ + ]]> +

Given two documents $doc1 and $doc2, the following expression + returns a map representing the employees who are present in the first document + but not the second:

+ map:remove(map-for-key('emp-name-key', $doc2) => map:keys())]]> +
+
+
+ + +

New in 4.0.

+
+
+
+ + diff --git a/specifications/xslt-40/src/xslt.xml b/specifications/xslt-40/src/xslt.xml index 903adf7c38..3d7359d9c6 100644 --- a/specifications/xslt-40/src/xslt.xml +++ b/specifications/xslt-40/src/xslt.xml @@ -35269,9 +35269,12 @@ the same group, and the--> The xsl:key Declaration

The xsl:key - declaration is used to declare keys. The name attribute specifies the name - of the key. The value of the name attribute is an EQName, which is expanded as - described in . The match attribute is a Pattern; an xsl:key element applies to + declaration is used to declare keys. + The name attribute specifies the name + of the key. The value of the name attribute is + an EQName, which is expanded as + described in . The match attribute + is a Pattern; an xsl:key element applies to all nodes that match the pattern specified in the match attribute.

@@ -35280,7 +35283,8 @@ the same group, and the--> package that share the same name.

-

The key name is scoped to the containing package, and is available for use in calls to the +

The key name is scoped to the containing package, + and is available for use in calls to the key function within that package.

The value of the key may be specified either using the use attribute or by means of the contained sequence @@ -35293,9 +35297,10 @@ the same group, and the--> attribute.

-

If the use attribute is present, its value is an expression specifying the values of the key. The - expression will be evaluated with a singleton focus based on the node that - matches the pattern. The result of evaluating the expression is +

If the use attribute is present, its value is an + expression specifying the values of the key. The + expression will be evaluated with a singleton focus + based on the node that matches the pattern. The result of evaluating the expression is atomized.

Similarly, if a sequence constructor is present, it is used to determine the values of the @@ -35304,7 +35309,8 @@ the same group, and the--> atomized.

The expression in the - use attribute and the sequence constructor within an xsl:key + use attribute and the sequence constructor + within an xsl:key declaration are referred to collectively as the key specifier. The key specifier determines the values that may be used to find a node using this key. @@ -35363,7 +35369,8 @@ the same group, and the--> $collation) returns true. The effective collation for an xsl:key declaration is the collation specified in its collation attribute if present, resolved against the base URI of - the xsl:key element, or the default collation that is in scope for the xsl:key + the xsl:key element, or the + default collation that is in scope for the xsl:key declaration otherwise; the effective collation must be the same for all the xsl:key declarations making up a key.

@@ -35387,8 +35394,10 @@ the same group, and the-->

It is a static error if there are - several xsl:key declarations in a package with the same key name and - different effective values for the composite attribute.

+ several xsl:key declarations in a package + with the same key name and + different effective values + for the composite attribute.

It is possible to have:

@@ -35411,7 +35420,8 @@ the same group, and the--> nodes do not need to be unique).

-

An xsl:key declaration with higher import precedence does not override +

An xsl:key declaration with higher + import precedence does not override another of lower import precedence; all the xsl:key declarations in the stylesheet are effective regardless of their import precedence.

@@ -35419,6 +35429,10 @@ the same group, and the--> + + + + Keys and Streaming @@ -39767,6 +39781,11 @@ See of different types, two items in different groups could compare equal. Any change in behavior is confined to this edge case.

+ +

The rules for comparing values in keys have changed, + to align with the rules for maps. The changes affect edge cases involving rounding of numeric values + of different types, and the comparison of date/time values with and without timezones.

+