xsl-list
[Top] [All Lists]

Re: [xsl] how to make a group-by multiple attributes motionless

2019-09-25 17:55:49
This code passes Saxon's streamability tests:

<xsl:stylesheet version="3.0" xmlns:xs="http://www.w3.org/2001/XMLSchema";
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
    
  <xsl:mode streamable="yes"/>
    
  <xsl:template match="/">
   <out> 
    <xsl:fork>
        <xsl:for-each-group select="/*/row" group-by="((@* => copy-of() => 
sort((), function($x){name($x)})) ! (name() || '=' || string(.))) => 
string-join(' ')">
          <xsl:sequence select="current-group()"/>
        </xsl:for-each-group>
    </xsl:fork>
   </out>
  </xsl:template>
</xsl:stylesheet>

Note that the sort() function requires XPath 3.1 so its streamability analysis 
isn't covered in the XSLT 3.0 spec, but Saxon applies similar rules to 
functions such as fn:filter: if the first argument is grounded then the 
function is streamable.

The key here is the use of copy-of() to copy the attributes before sorting; 
this enables the compiler to know that the sort function isn't going to do any 
non-streamable navigation starting at the attribute node. In fact, after 
sorting you could equally well call a user-defined function that sorts using 
xsl:perform-sort.

Michael Kay
Saxonica

On 25 Sep 2019, at 22:44, Geert Bormans 
geert(_at_)gbormans(_dot_)telenet(_dot_)be 
<xsl-list-service(_at_)lists(_dot_)mulberrytech(_dot_)com> wrote:

All,

I a streaming XSLT 3.0, I have to group a series of elements by their 
attribute names and values
I have issues making the group-by motionless

In a simplified example

<rows>
    <row a="val-a-1" b="b-val"/>
    <row a="val-a-2" b="b-val"/>
    <row a="val-a-1" b="b-val"/>
    <row a="val-a-2"/>
</rows>

I need grouping this way

<rowgroups>
   <rowgroup hash="|a=val-a-1|b=b-val"/>
   <rowgroup hash="|a=val-a-2|b=b-val"/>
   <rowgroup hash="|a=val-a-2"/>
</rowgroups>

easily achieved this way

             <xsl:fork>
                <xsl:for-each-group select="*" 
group-by="string-join(@*/concat('|', name(), '=', .), '')">
                    <rowgroup hash="{current-grouping-key()}"/>
                </xsl:for-each-group>
            </xsl:fork>

but, I could have data like this (third line attribute order swapped)

<rows>
    <row a="val-a-1" b="b-val"/>
    <row a="val-a-2" b="b-val"/>
    <row b="b-val" a="val-a-1"/>
    <row a="val-a-2"/>
</rows>

and this basically gives me a fourth group using the code above

So I want to make sure that the attributes order can be controlled when I 
prepare the group-by, but any sorting attempt I make, leads to the group-by 
no longer being motionless

I would welcome your suggestions

Thanks

Met vriendelijke groeten,
Best regards,

Geert Bormans
XSL-List info and archive <http://www.mulberrytech.com/xsl/xsl-list>
EasyUnsubscribe <http://lists.mulberrytech.com/unsub/xsl-list/293509> (by 
email <>)
--~----------------------------------------------------------------
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
EasyUnsubscribe: http://lists.mulberrytech.com/unsub/xsl-list/1167547
or by email: xsl-list-unsub(_at_)lists(_dot_)mulberrytech(_dot_)com
--~--
<Prev in Thread] Current Thread [Next in Thread>