W3C home > Mailing lists > Public > public-xslt-40@w3.org > January 2021

Re: Processiing arrays in XSLT 4

From: Michael Kay <mike@saxonica.com>
Date: Tue, 12 Jan 2021 08:49:44 +0000
Message-Id: <A0E9CFDB-C242-4BAF-807D-27224C8DB9CE@saxonica.com>
Cc: public-xslt-40@w3.org
To: Mukul Gandhi <gandhi.mukul@gmail.com>
This suggests several separate ideas here:

(a) iterating using an explicit index. This is of course possible today using <xsl:for-each select="1 to N"> or <xsl:iterate select="1 to N">; within the "loop" the index is available both as "." and as "position()". When iterating over a sequence, this style has always been a little clumsy because the traditional way of accessing the Nth item of a sequence ($seq[X]) doesn't work because the focus inside the predicate is wrong. This objection doesn't apply when iterating over an array, where we can use $array(.) or $array(position()). However, I feel that it shouldn't be necessary to use indexing every time you want to iterate over an array. This is, I guess, primarily an aesthetic objection: it introduces a bit of machinery to the operation that feels like you're no longer saying what you want to do, you are saying how it should be done. Other languages have all moved in the direction of allowing iteration over collections without explicit indexing, and it feels like the right thing to do.

(b) iterating over an array using the same constructs used to iterate over a sequence (xsl:for-each, xsl:iterate, perhaps also xsl:for-each-group). There is some attraction in this, and the only reason it isn't possible is that an array is a sequence of length 1, and these constructs apply to ANY sequence including a sequence of length 1. However, perhaps we could distinguish array iteration using an attribute, such as

<xsl:for-each select="$input" over="array"> 

or perhaps

<xsl:for-each array="$input">

to indicate that we are iterating over an array rather than a sequence; we could then use the same extension for xsl:for-each and xsl:for-each-group. I quite like this idea, but it leaves the problem of how to refer to the current value and position, given that the current value is no longer (necessarily) a single item.

We can handle this by binding variables:

<xsl:for-each array="$input" bind="this">
   <xsl:value-of select="$this" />

And again we could introduce this mechanism for all three constructs. We could also allow over="map" where the "current value" is a singleton map containing the key-value pair.

This leaves some details about how you bind position, and whether binding variables are mandatory when processing an array (or how it should work if they aren't mandatory), but it feels like a promising direction.

(c) I also detect in your proposal the idea of using an attribute name as a binding variable. Instead of

<xsl:for-each select="$input" bind="this">

one could use

<xsl:for-each this="$input">

There are attractions, and I think the idea is feasible, but it feels like a major departure from existing conventions, where the attribute names are defined in the language spefication and only their values can be chosen by the user. However, another proposal for 4.0 is to use extension instructions for xsl:call-template, so

<xsl:call-template name="do:something">
  <xsl:with-param name="input" select="23"/>

can be written as

<do:something input="23"/>

which would break with convention in the same way.

Michael Kay

> On 12 Jan 2021, at 07:37, Mukul Gandhi <gandhi.mukul@gmail.com> wrote:
> On Sat, Jan 9, 2021 at 10:08 PM Michael Kay <mike@saxonica.com <mailto:mike@saxonica.com>> wrote:
> It seems a no-brainer to provide an XSLT instruction along the lines
> <xsl:for-each-member select="array">
>   ....
> </xsl:for-each>
> to process the members of a supplied array.
> The question is: within the body of this instruction, how should one refer to the current member of the array?
> To do this, I'd like to propose enhancements to syntax of xsl:iterate. Something, along the following lines,
> 1) Let the XSLT 4.0 variable 'A' represents an array.
> for e.g,
> <xsl:variable name="A" select="array { 1, 2, 5, 7 }"/>
> 2) Then do following,
> <xsl:iterate idx="1 to array:size($A)">
>    <!-- do something with $A($idx) -->
> </xsl:iterate>
> Notes:
> Currently XSLT 4.0 xsl:iterate instruction is defined as follows (quoted from XSLT 4.0 spec, which I propose to be retained in XSLT 4.0),
> <xsl:iterate
>    select = expression>
>    <!-- Content: (xsl:param*, xsl:on-completion?, sequence-constructor) -->
> </xsl:iterate>
> Where, xsl:iterate/@select contains an expression which is evaluated to produce a sequence, called the input sequence.
> -- 
> Regards,
> Mukul Gandhi

Received on Tuesday, 12 January 2021 08:50:03 UTC

This archive was generated by hypermail 2.4.0 : Tuesday, 12 January 2021 08:50:03 UTC