|
declare namespace map = "http://www.w3.org/2005/xpath-functions/map";
|
|
declare namespace array = "http://www.w3.org/2005/xpath-functions/array";
|
|
|
|
declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization";
|
|
|
|
declare option output:method 'adaptive';
|
|
|
|
declare function local:fold-left-append($seq as item()*, $zero as array(*)) as array(*) {
|
|
if (empty($seq))
|
|
then $zero
|
|
else local:fold-left-append(tail($seq), array:append($zero, head($seq)?*))
|
|
};
|
|
|
|
declare variable $xslt1 :=
|
|
|
|
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
|
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
|
xmlns:array="http://www.w3.org/2005/xpath-functions/array"
|
|
xmlns:mf="http://example.com/mf"
|
|
exclude-result-prefixes="#all"
|
|
version="3.0">
|
|
|
|
<xsl:mode on-no-match="shallow-skip"/>
|
|
|
|
<xsl:output method="adaptive"/>
|
|
|
|
<xsl:function name="mf:fold-left-append" as="array(*)">
|
|
<xsl:param name="seq" as="item()*"/>
|
|
<xsl:param name="zero" as="array(*)"/>
|
|
<xsl:sequence
|
|
select="if (empty($seq))
|
|
then $zero
|
|
else mf:fold-left-append(tail($seq), array:append($zero, head($seq)?*))"/>
|
|
</xsl:function>
|
|
|
|
<xsl:template match="root/items">
|
|
<xsl:variable name="sequence-of-arrays" as="array(node()*)*">
|
|
<xsl:for-each-group select="item" composite="yes" group-by="foo, bar">
|
|
<xsl:sequence select="array {{ current-group() }}"/>
|
|
</xsl:for-each-group>
|
|
</xsl:variable>
|
|
<xsl:sequence select="mf:fold-left-append($sequence-of-arrays, [])"/>
|
|
</xsl:template>
|
|
|
|
</xsl:stylesheet>;
|
|
|
|
let $xquery-result :=
|
|
local:fold-left-append(
|
|
for $item at $pos in root/items/item
|
|
group by $key1 := $item/foo, $key2 := $item/bar
|
|
order by head($pos)
|
|
return
|
|
array { $item },
|
|
[]
|
|
),
|
|
$xslt-result :=
|
|
transform(map {
|
|
'source-node' : .,
|
|
'stylesheet-node' : $xslt1,
|
|
'delivery-format' : 'raw'
|
|
})?output
|
|
return
|
|
deep-equal($xquery-result, $xslt-result)
|