xsl-list
[Top] [All Lists]

Re: [xsl] XSLT3 generic grouping functions

2020-07-09 05:23:15
Hi Martin, 

Thanks you for theses feedbacks.

You are right, the function could be more generic with any sequence of nodes as 
param. I'm use to always perform adjacent grouping within a XML document tree 
in a specific context, in document order. But it's true there might be other 
usecases.
I set a new issue here : 
https://github.com/ELSGestion/els-sie-xsl-lib/issues/17 

Yes <xsl:copy select="$wrapper"> is quite more readable instead of this dummy 
loop to change the context. I commited this refacto.

Liebe Grüße

Matthieu

-----Message d'origine-----
De : Martin Honnen martin(_dot_)honnen(_at_)gmx(_dot_)de 
[mailto:xsl-list-service(_at_)lists(_dot_)mulberrytech(_dot_)com] 
Envoyé : mercredi 8 juillet 2020 11:36
À : xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
Objet : Re: [xsl] XSLT3 generic grouping functions

Am 08.07.2020 um 11:24 schrieb Matthieu RICAUD-DUSSARGET
m(_dot_)ricaud-dussarget(_at_)lefebvre-sarrut(_dot_)eu:
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-common_xml.xsl


There's also some generic xsl to nest titles
(https://github.com/ELSGestion/els-sie-xsl-lib/blob/master/src/main/xs
l/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/xs
l/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 (there's 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?
--~----------------------------------------------------------------
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>