Re: [xsl] XSLT3 generic grouping functions

Subject: Re: [xsl] XSLT3 generic grouping functions
From: "Martin Honnen martin.honnen@xxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Wed, 8 Jul 2020 09:36:07 -0000
Am 08.07.2020 um 11:24 schrieb Matthieu RICAUD-DUSSARGET
m.ricaud-dussarget@xxxxxxxxxxxxxxxxxx:
Hi all,

While teaching XSLT, someone ask if it was possible to have a kind of
generic function to group XML elements.

I first answer the only way to do it was to use (eventually nested)
<xsl:for-each-group> instruction with specific conditions according to
the data.

Later, as I was discovering XSLT3, I realize the grouping condition
might be sent as an higher-order-function parameter, which lead me to
write some generic grouping functions to wrap XML elements (see example
below).

The original code can be found on github at

https://github.com/ELSGestion/els-sie-xsl-lib/blob/master/src/main/xsl/els-co
mmon_xml.xsl


Theres also some generic xsl to nest titles

(https://github.com/ELSGestion/els-sie-xsl-lib/blob/master/src/main/xsl/nest-
titles.xsl)
and a specific implementation of it to nest HTML titles

(https://github.com/ELSGestion/els-sie-xsl-lib/blob/master/src/main/xsl/nest-
html-titles.xsl)

Working examples can be found in the test folder https://github.com/ELSGestion/els-sie-xsl-lib/tree/master/src/test, as xspec unit test or xspec driven integration tests.

I actually have a bug with Saxon 9.9
(https://saxonica.plan.io/issues/4636) on the generic starting-with
grouping function, but this is an occasion to share theses grouping
libraries J

Any comments, feedbacks or similar code implementation are welcome !

Cheers

Matthieu Ricaud-Dussarget

Example of generic adjacent grouping function used to define a specific
by-name grouping implementation (theres a similar set of functions
for starting-with) :

<xd:doc>

<xd:desc>

<xd:p>Wrap adjacent elements into a new "wrapper" element</xd:p>

     <xd:p>CAUTION : any text, pi, comments within context will be
loose</xd:p>

</xd:desc>

   <xd:param name="context">Parent of the adjacent elements to
wrap</xd:param>

   <xd:param name="adjacent.function">Xpath function to set the
adjacency condition</xd:param>

<xd:param name="wrapper">Element wrapper</xd:param>

   <xd:param name="keep-context">Say if the context should be kept or
not in the result</xd:param>

   <xd:return>context (or its content) with wrapped adjacent
element</xd:return>

</xd:doc>

<xsl:function name="els:wrap-elements-adjacent" as="node()*">

<xsl:param name="context" as="element()"/>

<xsl:param name="adjacent.function"/> <!--as="xs:string"-->

<xsl:param name="wrapper" as="element()"/>

<xsl:param name="keep-context" as="xs:boolean"/>

<xsl:variable name="content" as="item()*">

     <xsl:for-each-group select="$context/*"
group-adjacent="$adjacent.function(.)">


I would certainly prefer to write a "generic" function that expects a
parameter with the grouping population as a sequence of nodes and then use

<xsl:for-each-group select="$population" ...

I don't think for-each-group adjacent is meant to be used only for child
elements of a parent, if you want to use it in a generic way then
provide a population sequence you want to group.



<xsl:choose>


<xsl:when test="current-grouping-key()">

<xsl:for-each select="$wrapper">

<xsl:copy>

<xsl:copy-of select="@*"/>

Doesn't <xsl:copy select="$wrapper">

suffice in XSLT 3?

Why the xsl:for-each?

Current Thread