Skip to content

[xslt] Constructing arrays #113

Description

@michaelhkay

I've felt for a while that the current proposal for xsl:array is messy. It's both semantically and syntactically messy with it's composite=yes|no attribute and the xsl:array-member child. I've been using it doing XML to JSON conversion and you get a lot of stuff like this:

<xsl:template match="closed_auctions">
      <xsl:array>
         <xsl:for-each select="closed_auction">
            <xsl:map>
               <xsl:apply-templates select="*"/>
            </xsl:map>
         </xsl:for-each>
      </xsl:array>
   </xsl:template>

Almost invariably, xsl:array has xsl:for-each or xsl:apply-templates as a child. So how about allowing:

<xsl:template match="closed_auctions">
         <xsl:for-each select="closed_auction" form="array">
            <xsl:map>
               <xsl:apply-templates select="*"/>
            </xsl:map>
         </xsl:for-each>
   </xsl:template>

The semantics here is that xsl:for-each delivers an array in which there is one member for each item in the input sequence. This cleanly eliminates the need for composite=yes|no and xsl:array-member: you can create a "composite" array using

<xsl:for-each select="1 to 5" form="array">
   <xsl:sequence select="., .+1"/>
</xsl:for-each>

which delivers [(1,2), (2,3), (3,4), (4,5), (5,6)].

The attribute form="array" can also appear on xsl:apply-templates and xsl:for-each-group. In the latter case each group produces one member of the resulting array:

<xsl:for-each-group select="0 to 9" group-adjacent="0 idiv 5" form="array">
   <xsl:sequence select="current-group()"/>
</xsl:for-each-group>

delivers [(0,1,2,3,4), (5,6,7,8,9)]

The attribute form="sequence" is the default and specifies the current behaviour.

I've been wondering also about extending this to form="map". In most cases when you construct a map from an input sequence, both the key and the value are functions of the input item. So instead of:

<xsl:template match="regions">
      <xsl:map>
         <xsl:for-each select="*">
            <xsl:map-entry key="name()">
               <xsl:array>
                  <xsl:for-each select="item">
                     <xsl:array-member>
                        <xsl:apply-templates select="."/>
                     </xsl:array-member>
                  </xsl:for-each>
               </xsl:array>
            </xsl:map-entry>
         </xsl:for-each>
      </xsl:map>
   </xsl:template>

we could write:

<xsl:template match="regions">
         <xsl:for-each select="*" form="map" key="name()">
                  <xsl:apply-templates select="item" form="array"/>
         </xsl:for-each>
 </xsl:template>

which strikes me as an improvement...

Metadata

Metadata

Assignees

No one assigned

    Labels

    EnhancementA change or improvement to an existing featureXSLTAn issue related to XSLT

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions