From a109b606ef532e3ffedc351befb0849961c20161 Mon Sep 17 00:00:00 2001 From: Michael Kay Date: Sun, 23 Jun 2024 19:44:49 +0100 Subject: [PATCH] Add xsl:item and xsl:sequence/@as --- .../xslt-40/src/element-catalog.xml | 17 ++ specifications/xslt-40/src/xslt.xml | 264 +++++++++++------- 2 files changed, 176 insertions(+), 105 deletions(-) diff --git a/specifications/xslt-40/src/element-catalog.xml b/specifications/xslt-40/src/element-catalog.xml index f0c296999..1bb2d8887 100644 --- a/specifications/xslt-40/src/element-catalog.xml +++ b/specifications/xslt-40/src/element-catalog.xml @@ -1187,6 +1187,23 @@ + + + + + + + + + + + + + + + + + diff --git a/specifications/xslt-40/src/xslt.xml b/specifications/xslt-40/src/xslt.xml index 017fa7b62..7b38a5196 100644 --- a/specifications/xslt-40/src/xslt.xml +++ b/specifications/xslt-40/src/xslt.xml @@ -1641,8 +1641,8 @@ xsl:copy-of;

-

an instruction that returns an arbitrary sequence by evaluating an XPath - expression: xsl:sequence;

+

instructions that returns an arbitrary values by evaluating an XPath + expression: xsl:item, xsl:sequence;

instructions that cause conditional or repeated evaluation of nested @@ -3210,26 +3210,26 @@ as="map(xs:integer, xs:double)" visibility="public"> <xsl:param name="real" as="xs:double"/> <xsl:param name="imaginary" as="xs:double"/> - <xsl:sequence select="{ 0: $real, 1: $imaginary }"/> + <xsl:item select="{ 0: $real, 1: $imaginary }"/> </xsl:function> <xsl:function name="f:real" as="xs:double" visibility="public"> <xsl:param name="complex" as="map(xs:integer, xs:double)"/> - <xsl:sequence select="$complex(0)"/> + <xsl:item select="$complex(0)"/> </xsl:function> <xsl:function name="f:imag" as="xs:double" visibility="public"> <xsl:param name="complex" as="map(xs:integer, xs:double)"/> - <xsl:sequence select="$complex(1)"/> + <xsl:item select="$complex(1)"/> </xsl:function> <xsl:function name="f:add" as="map(xs:integer, xs:double)" visibility="public"> <xsl:param name="x" as="map(xs:integer, xs:double)"/> <xsl:param name="y" as="map(xs:integer, xs:double)"/> - <xsl:sequence select=" + <xsl:item select=" f:complex-number( f:real($x) + f:real($y), f:imag($x) + f:imag($y))"/> @@ -3239,7 +3239,7 @@ as="map(xs:integer, xs:double)" visibility="public"> <xsl:param name="x" as="map(xs:integer, xs:double)"/> <xsl:param name="y" as="map(xs:integer, xs:double)"/> - <xsl:sequence select=" + <xsl:item select=" f:complex-number( f:real($x)*f:real($y) - f:imag($x)*f:imag($y), f:real($x)*f:imag($y) + f:imag($x)*f:real($y))"/> @@ -5945,7 +5945,7 @@ as="xs:string?" visibility="public"> <xsl:param name="line" as="xs:string" /> - <xsl:sequence select="normalize-space($line)" /> + <xsl:item select="normalize-space($line)" /> </xsl:function>

Because the function is declared public, it can be overridden by a @@ -6093,7 +6093,7 @@ there is no need to make it needlessly implausible.

--> as="xs:string"> <xsl:param name="field" as="xs:string" /> - <xsl:sequence select="$field" /> + <xsl:item select="$field" /> </xsl:function>

As can be seen, the function does nothing but return its input; its only @@ -6191,7 +6191,7 @@ there is no need to make it needlessly implausible.

--> <xsl:param name="line" as="xs:string" /> <xsl:variable name="norm-line" select="normalize-space(xsl:original($line))" /> - <xsl:sequence select="if (string-length($norm-line) > 0) + <xsl:item select="if (string-length($norm-line) > 0) then $norm-line else ()" /> </xsl:function> @@ -11079,7 +11079,7 @@ and version="1.0" otherwise.

- + ]]>

Note how the item type declaration has implicitly declared a constructor function @@ -11645,13 +11645,15 @@ and version="1.0" otherwise.

of zero, one, or more items as its result. For most XSLT instructions, these items are nodes, but some instructions (such as - xsl:sequence and xsl:copy-of) can also + xsl:item, xsl:sequence, + and xsl:copy-of) can also produce atomic values or function items. Several instructions, such as xsl:element, return a newly constructed parentless node (which may have its own attributes, namespaces, children, and other descendants). Other instructions, such as xsl:if, pass on the items produced by their own nested - sequence constructors. The xsl:sequence instruction may return + sequence constructors. The xsl:item and + xsl:sequence instructions may return atomic values, function items, or existing nodes.

@@ -11700,8 +11702,8 @@ and version="1.0" otherwise.

or insert separators between adjacent items. This means it is often inappropriate to use xsl:value-of in the body of xsl:variable or xsl:function, especially when the intent is to return an atomic result. - The xsl:sequence instruction is designed for this purpose, and - is usually a better choice. + The xsl:item and xsl:sequence instructions are + designed for this purpose, and are usually a better choice.

The result of a function, or the value of a variable, may contain nodes (such as elements, attributes, and text nodes) that are not attached to any parent node @@ -11730,7 +11732,9 @@ and version="1.0" otherwise.

xsl:break, xsl:catch, xsl:fallback, xsl:for-each, - xsl:for-each-group, xsl:fork, xsl:if, xsl:iterate, + xsl:for-each-group, + xsl:fork, + xsl:if, xsl:item, xsl:iterate, xsl:matching-substring, xsl:non-matching-substring, xsl:on-completion, xsl:otherwise, xsl:perform-sort, @@ -11972,8 +11976,8 @@ and version="1.0" otherwise.

sequence of five text nodes, which are concatenated without space separation.

It is important to be aware of the distinction between - xsl:sequence, which returns the value of its - select expression unchanged, and xsl:value-of, + xsl:item and xsl:sequence, which return the value of the + select expression unchanged (except for type coercion), and xsl:value-of, which constructs a text node.

@@ -17092,7 +17096,7 @@ and version="1.0" otherwise.

The value of the following variable is a sequence of integers (2, 4, 6):

<xsl:variable name="seq" as="xs:integer*"> <xsl:for-each select="1 to 3"> - <xsl:sequence select=".*2"/> + <xsl:item select=".*2"/> </xsl:for-each> </xsl:variable>

The value of the following variable is a sequence of parentless attribute @@ -19660,7 +19664,7 @@ and version="1.0" otherwise.

as="node()"/> <xsl:param name="get-direct-children" as="fn(node()) as node()*"/> - <xsl:sequence select=" + <xsl:item select=" some $sub in $get-direct-children($superior) satisfies ($sub is $subordinate or f:is-subordinate($sub, $subordinate, @@ -20038,7 +20042,7 @@ and version="1.0" otherwise.

<xsl:variable name="isValid" as="xs:boolean"> <xsl:evaluate xpath="$validityCondition"> - <xsl:fallback><xsl:sequence select="true()"/></xsl:fallback> + <xsl:fallback><xsl:item select="true()"/></xsl:fallback> </xsl:evaluate> </xsl:variable> @@ -21753,90 +21757,143 @@ and version="1.0" otherwise.

.

- - Constructing Sequences - -

The xsl:sequence instruction may be used within a sequence constructor to construct a - sequence of nodes, atomic values, and/or function - items. This sequence is returned as the result of the instruction. Unlike - most other instructions, xsl:sequence can return a sequence - containing existing nodes, rather than constructing new nodes. When - xsl:sequence is used to select atomic values or function items, the effect is very similar to the - xsl:copy-of instruction.

-

The items comprising the result sequence are evaluated either using - the select attribute, or using the contained . These are mutually exclusive; if the instruction - has a select attribute, then it must have no children - other than xsl:fallback instructions. If there is no - select attribute and no contained , the result is an empty sequence.

-

- -

For the elements xsl:sequence, xsl:on-empty, - xsl:on-non-empty, xsl:when, - xsl:otherwise, xsl:matching-substring, - and xsl:non-matching-substring, - it is a static error if the - select attribute is present - and the instruction has children other than xsl:fallback.

- -

-

Any contained xsl:fallback instructions are ignored by an XSLT 2.0 - or 3.0 processor, but can be used to define - fallback behavior for an XSLT 1.0 processor running in forwards compatibility - mode.

- - Constructing a Sequence of Integers -

The following code:

- <xsl:variable name="values" as="xs:integer*"> + + Constructing Items and Sequences + + Constructing Items + + + The xsl:item instruction is introduced. The aim is to make code more readable, + by avoiding the need to write xsl:sequence when it is known that the value + will be a single item. + + + +

The xsl:item instruction may be used within a sequence constructor to construct a + node, atomic value, or function + item. This item is returned as the result of the instruction. Unlike + most other instructions, xsl:item can return an existing node, + rather than constructing new nodes. The semantics are identical to xsl:sequence, + except that the as attribute is constrained to be an item type rather than + a sequence type, and the default value is item().

+

The result item is evaluated either using + the select attribute, or using the contained . These are mutually exclusive; if the instruction + has a select attribute, then it must have no children + other than xsl:fallback instructions . + Unlike other similar instructions, there must be either a select attribute + or a non-empty , + since an empty sequence is not a permitted result.

+ +

Any contained xsl:fallback instructions are ignored by an XSLT 4.0 processor, + but can be used to define + fallback behavior for processors implementing an earlier version of XSLT.

+

The xsl:item instruction does not do anything that could not be achieved using + an xsl:sequence instruction, but it improves the readability of code by highlighting to the + reader that the value will always be a singleton.

+ + A function with a boolean result +

The following function:

+ <xsl:function name="f:is-positive"> + <xsl:param name="in"/> + <xsl:item select="$n gt 0"/> + </xsl:function> + +

raises a type error if $in is an empty sequence, + because the result of xsl:item cannot be an empty sequence. +

+
+
+ + Constructing Sequences + + + The xsl:sequence instruction now has an as attribute to define + the expected type of the result. + + + +

The xsl:sequence instruction may be used within a sequence constructor to construct a + sequence of nodes, atomic values, and/or function + items. This sequence is returned as the result of the instruction. Unlike + most other instructions, xsl:sequence can return a sequence + containing existing nodes, rather than constructing new nodes. When + xsl:sequence is used to select atomic values or function items, the effect is very similar to the + xsl:copy-of instruction.

+

The items comprising the result sequence are evaluated either using + the select attribute, or using the contained . These are mutually exclusive; if the instruction + has a select attribute, then it must have no children + other than xsl:fallback instructions. If there is no + select attribute and no contained , the result is an empty sequence.

+

If an as attribute is present, the result of this evaluation is converted to the specified + sequence type by applying the .

+

+ +

For the elements xsl:item, xsl:sequence, xsl:on-empty, + xsl:on-non-empty, xsl:when, + xsl:otherwise, xsl:matching-substring, + and xsl:non-matching-substring, + it is a static error if the + select attribute is present + and the instruction has children other than xsl:fallback.

+ +

+

Any contained xsl:fallback instructions are ignored by an XSLT 2.0 + or 3.0 processor, but can be used to define + fallback behavior for an XSLT 1.0 processor running in forwards compatibility + mode.

+ + Constructing a Sequence of Integers +

The following code:

+ <xsl:variable name="values" as="xs:integer*"> <xsl:sequence select="(1,2,3,4)"/> <xsl:sequence select="(8,9,10)"/> </xsl:variable> <xsl:value-of select="sum($values)"/> -

produces the output: 37 -

-
- - Using xsl:for-each to Construct a Sequence -

The following code constructs a sequence containing the value of the - @price attribute for selected elements (which we assume to be - typed as xs:decimal), or a computed price for those elements that - have no @price attribute. It then returns the average price:

- <xsl:variable name="prices" as="xs:decimal*"> +

produces the output: 37 +

+
+ + Using xsl:for-each to Construct a Sequence +

The following code constructs a sequence containing the value of the + @price attribute for selected elements (which we assume to be + typed as xs:decimal), or a computed price for those elements that + have no @price attribute. It then returns the average price:

+ <xsl:variable name="prices" as="xs:decimal*"> <xsl:for-each select="//product"> <xsl:choose> - <xsl:when test="@price"> - <xsl:sequence select="@price"/> - </xsl:when> - <xsl:otherwise> - <xsl:sequence select="@cost * 1.5"/> - </xsl:otherwise> + <xsl:when test="@price" select="@price"/> + <xsl:otherwise select="@cost * 1.5"/> </xsl:choose> </xsl:for-each> </xsl:variable> <xsl:value-of select="avg($prices)"/> -

Note that the existing @price attributes could equally have been - added to the $prices sequence using xsl:copy-of or - xsl:value-of. However, xsl:copy-of would - create a copy of the attribute node, which is not needed in this situation, while - xsl:value-of would create a new text node, which then has to - be converted to an xs:decimal. Using xsl:sequence, - which in this case atomizes the existing attribute node and adds an - xs:decimal atomic value to the result sequence, is a more direct - way of achieving the same result.

-

This example could alternatively be solved at the XPath level:

- <xsl:value-of select="avg(//product/(+@price, @cost*1.5)[1])"/> -

The apparently redundant + operator is there to atomize the attribute - value: the expression on the right hand side of the / operator must - not return a sequence containing both nodes and - non-nodes (atomic values or function items).

-
- -

The main use case for allowing xsl:sequence to contain a sequence - constructor is to allow the instructions within an xsl:fork - element to be divided into groups.

-

It can also be used to limit the scope of local variables or of standard - attributes such as [xsl:]default-collation.

-
-
+

Note that the existing @price attributes could equally have been + added to the $prices sequence using xsl:copy-of or + xsl:value-of. However, xsl:copy-of would + create a copy of the attribute node, which is not needed in this situation, while + xsl:value-of would create a new text node, which then has to + be converted to an xs:decimal. Using xsl:sequence, + which in this case atomizes the existing attribute node and adds an + xs:decimal atomic value to the result sequence, is a more direct + way of achieving the same result.

+

This example could alternatively be solved at the XPath level:

+ <xsl:value-of select="avg(//product/(+@price, @cost*1.5)[1])"/> +

The apparently redundant + operator is there to atomize the attribute + value: the expression on the right hand side of the / operator must + not return a sequence containing both nodes and + non-nodes (atomic values or function items).

+
+ +

The main use case for allowing xsl:sequence to contain a sequence + constructor is to allow the instructions within an xsl:fork + element to be divided into groups.

+

It can also be used to limit the scope of local variables or of standard + attributes such as [xsl:]default-collation, and to define a scope + for xsl:on-empty and xsl:on-non-empty + instructions.

+
+ +
Numbering @@ -27201,13 +27258,10 @@ the same group, and the--> initial-value="{}"> <xsl:accumulator-rule match="book"> <xsl:choose> - <xsl:when test="map:contains($value, @publisher)"> - <xsl:sequence select="map:put($value, string(@publisher), + <xsl:when test="map:contains($value, @publisher)" + select="map:put($value, string(@publisher), $value(@publisher)+1)"/> - </xsl:when> - <xsl:otherwise> - <xsl:sequence select="map:put($value, string(@publisher), 1)"/> - </xsl:otherwise> + <xsl:otherwise select="map:put($value, string(@publisher), 1)"/> </xsl:choose> </xsl:accumulator-rule> </xsl:accumulator> @@ -28439,7 +28493,7 @@ the same group, and the--> <xsl:source-document streamable="yes" href="emps.xml"> <xsl:for-each select="*/emp"> - <xsl:sequence select="."/> + <xsl:item select="."/> </xsl:for-each> </xsl:source-document> @@ -28469,15 +28523,15 @@ the same group, and the-->

The content of the xsl:for-each instruction is a which itself has a single - operand, the xsl:sequence instruction.

+ operand, the xsl:item instruction.

-

The xsl:sequence instruction is evaluated once for each +

The xsl:item instruction is evaluated once for each emp child, with that child as context item and in a posture. This instruction uses the . The of the select expression is . This means that the result of the - xsl:sequence instruction is and .

+ xsl:item instruction is and .

The result of the trivial sequence constructor contained in the