xsl-list
[Top] [All Lists]

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

2020-09-16 17:47:40
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>


-- 
Graydon Saunders  | graydonish(_at_)gmail(_dot_)com
Þæs oferéode, ðisses swá mæg.
-- Deor  ("That passed, so may this.")
--~----------------------------------------------------------------
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>