xsl-list
[Top] [All Lists]

Re: [xsl] xsl:for-each-group help needed !

2020-09-17 01:18:16
Thanks a lot, Martin, Gerrit, Dimitre, Graydon ! I now need half a day to understand all your solutions, translate them to my real data structure, and choose the clearest one !

Thanks again,
Christophe

Le 17/09/2020 à 00:47, Graydon graydon(_at_)marost(_dot_)ca a écrit :
On 16.09.2020 23:19, Christophe Marchand cmarchand(_at_)oxiane(_dot_)com wrote:
[group the blocks]
Here is a sample input :

<blocks>
    <block id="i1">content</block>
    <block id="i2" width="33">content</block>
    <block id="i3" width="67">content</block>
    <block id="i4" width="50">content</block>
    <block id="i5" width="50">content</block>
    <block id="i6" width="25">content</block>
    <block id="i7" width="55">content</block>
    <block id="i8" width="20">content</block>
    <block id="i9">content</block>
</blocks>

Here is the expected output :

<blocks>
    <block id="i1">content</block>
    <block type="composite">
      <block id="i2" width="33">content</block>
      <block id="i3" width="67">content</block>
    </block>
    <block type="composite">
      <block id="i4" width="50">content</block>
      <block id="i5" width="50">content</block>
    </block>
    <block type="composite">
      <block id="i6" width="25">content</block>
      <block id="i7" width="55">content</block>
      <block id="i8" width="20">content</block>
    </block>
    <block id="i9">content</block>
</blocks>

I have no idea of which form of for-each-group I have to use...
It's not as short as I hoped, but a two-pass approach can avoid an
accumulator:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet exclude-result-prefixes="xs math xd" version="3.0"
   xmlns:math="http://www.w3.org/2005/xpath-functions/math"; 
xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl";
   xmlns:xs="http://www.w3.org/2001/XMLSchema"; 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
   <xd:doc scope="stylesheet">
     <xd:desc>
       <xd:p><xd:b>Created on:</xd:b> Sep 16, 2020</xd:p>
       <xd:p><xd:b>Author:</xd:b> graydon</xd:p>
       <xd:p />
     </xd:desc>
   </xd:doc>
   <xsl:mode name="numbers" on-no-match="shallow-copy" />
   <xsl:mode name="group" on-no-match="shallow-copy" />
   <xsl:variable as="element(blocks)" name="input">
     <blocks>
       <block id="i1">content</block>
       <block id="i2" width="33">content</block>
       <block id="i3" width="67">content</block>
       <block id="i4" width="50">content</block>
       <block id="i5" width="50">content</block>
       <block id="i6" width="25">content</block>
       <block id="i7" width="55">content</block>
       <block id="i8" width="20">content</block>
       <block id="i9">content</block>
     </blocks>
   </xsl:variable>
   <xd:doc>
     <xd:desc>main template</xd:desc>
   </xd:doc>
   <xsl:template name="xsl:initial-template">
     <xsl:variable name="pass1">
       <xsl:apply-templates mode="numbers" select="$input" />
     </xsl:variable>
     <xsl:apply-templates mode="group" select="$pass1" />
   </xsl:template>
   <xd:doc>
     <xd:desc>add numbers to the blocks</xd:desc>
   </xd:doc>
   <xsl:template match="block" mode="numbers">
     <xsl:copy>
       <xsl:apply-templates mode="numbers" select="@*" />
       <xsl:if test="@width">
         <xsl:attribute name="count" select="(preceding-sibling::block/@width => sum()) 
mod 100" />
       </xsl:if>
       <xsl:apply-templates mode="numbers" select="node()" />
     </xsl:copy>
   </xsl:template>
   <xd:doc>
     <xd:desc>do the grouping</xd:desc>
   </xd:doc>
   <xsl:template match="blocks" mode="group">
     <xsl:copy>
       <xsl:apply-templates mode="group" select="@*" />
       <xsl:for-each-group group-starting-with="block[@count/number() lt 
preceding-sibling::block[1]/@count/number()]"
         select="*">
         <xsl:for-each-group group-adjacent="(self::block[exists(@count)], false())[1]" 
select="current-group()">
           <xsl:choose>
             <xsl:when test="current-grouping-key()">
               <block type="composite">
                 <xsl:apply-templates mode="group" select="current-group()" />
               </block>
             </xsl:when>
             <xsl:otherwise>
               <xsl:apply-templates mode="group" select="current-group()" />
             </xsl:otherwise>
           </xsl:choose>
         </xsl:for-each-group>
       </xsl:for-each-group>
     </xsl:copy>
   </xsl:template>
   <xd:doc>
     <xd:desc>remove count attributes</xd:desc>
   </xd:doc>
   <xsl:template match="@count" mode="group">
     <!-- thud -->
   </xsl:template>
</xsl:stylesheet>

produces:

<?xml version="1.0" encoding="UTF-8"?>
<blocks>
   <block id="i1">content</block>
   <block type="composite">
     <block id="i2" width="33">content</block>
     <block id="i3" width="67">content</block>
   </block>
   <block type="composite">
     <block id="i4" width="50">content</block>
     <block id="i5" width="50">content</block>
   </block>
   <block type="composite">
     <block id="i6" width="25">content</block>
     <block id="i7" width="55">content</block>
     <block id="i8" width="20">content</block>
   </block>
   <block id="i9">content</block>
</blocks>


--~----------------------------------------------------------------
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>