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

Subject: Re: [xsl] xsl:for-each-group help needed !
From: "Imsieke, Gerrit, le-tex gerrit.imsieke@xxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Thu, 17 Sep 2020 14:26:48 -0000
Hi Martin,

Does your code handle this 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="i6a" width="80">content</block>
  <block>content</block>
  <block id="i7" width="55">content</block>
  <block id="i8" width="20">content</block>
  <block id="i9">content</block>
</blocks>

i6 and i6a, taken together, have a width of 105. I guess then i6a needs to be on a new line.

I introduced an accumulator that can have two values:

<xsl:accumulator name="width" as="xs:integer+" initial-value="0">
  <xsl:accumulator-rule match="blocks" select="0"/>
  <xsl:accumulator-rule match="block"
    select="let $line-width-so-far := $value[1],
                $current-width := xs:integer((@width, 100)[1]),
                $would-be-line-width := $line-width-so-far
                                        + $current-width
                return (
                  if ($would-be-line-width gt 100)
                    then $current-width
                    else (),
                  $would-be-line-width
                )"/>
</xsl:accumulator>

If the line becomes too long, the width of the current block will be prepended to the would-be line length in the accumulator. So then there is a sequence of "line length if line wrap happened before current block" and "line length if line wrap did not happen before current block".
If, on the other hand, the would-be line length is less than or equal to 100, only a single value (the would-be line length) will go into the accumulator.


I added its accumulator value(s) to each block:

<blocks>
   <block id="i1" width="100" acc="100">content</block>
   <block type="composite">
      <block id="i2" width="33" acc="33 133">content</block>
      <block id="i3" width="67" acc="100">content</block>
   </block>
   <block type="composite">
      <block id="i4" width="50" acc="50 150">content</block>
      <block id="i5" width="50" acc="100">content</block>
   </block>
   <block id="i6" width="25" acc="25 125">content</block>
   <block id="i6a" width="80" acc="80 105">content</block>
   <block width="100" acc="100 180">content</block>
   <block type="composite">
      <block id="i7" width="55" acc="55 155">content</block>
      <block id="i8" width="20" acc="75">content</block>
   </block>
   <block id="i9" width="100" acc="100 175">content</block>
</blocks>

This has been achieved with a single grouping:

<xsl:template match="blocks">
<xsl:copy>
<xsl:for-each-group select="block"
group-starting-with="block[accumulator-before('width')[last()] gt 100]">
<xsl:choose>
<xsl:when test="count(current-group()) eq 1">
<xsl:apply-templates select="current-group()"/>
</xsl:when>
<xsl:otherwise>
<block type="composite">
<xsl:apply-templates select="current-group()"/>
</block>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>


Gerrit


On 17.09.2020 00:16, Martin Honnen martin.honnen@xxxxxx wrote:

I was wondering what output is wanted for


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

Neither my suggestion nor the above seem to only wrap the adjacent
block[@width] where the accumulator gives 100.

I complicated or strengthened my attempt as

 B  <xsl:template match="blocks">
 B B B  <xsl:copy>
 B B B B B  <xsl:for-each-group select="block" group-adjacent="not(@width)">
 B B B B B B B  <xsl:choose>
 B B B B B B B B B  <xsl:when test="current-grouping-key()">
 B B B B B B B B B B B  <xsl:apply-templates select="current-group()"/>
 B B B B B B B B B  </xsl:when>
 B B B B B B B B B  <xsl:otherwise>
 B B B B B B B B B B B  <xsl:for-each-group select="current-group()"
group-ending-with="block[accumulator-before('width') eq 100]">
 B B B B B B B B B B B B B  <xsl:choose>
 B B B B B B B B B B B B B B B  <xsl:when
test="current-group()[last()][accumulator-before('width') eq 100]">
 B B B B B B B B B B B B B B B B B  <block type="composite">
 B B B B B B B B B B B B B B B B B B B  <xsl:apply-templates select="current-group()"/>
 B B B B B B B B B B B B B B B B B  </block>
 B B B B B B B B B B B B B B B  </xsl:when>
 B B B B B B B B B B B B B B B  <xsl:otherwise>
 B B B B B B B B B B B B B B B B B  <xsl:apply-templates select="current-group()"/>
 B B B B B B B B B B B B B B B  </xsl:otherwise>
 B B B B B B B B B B B B B  </xsl:choose>
 B B B B B B B B B B B  </xsl:for-each-group>
 B B B B B B B B B  </xsl:otherwise>
 B B B B B B B  </xsl:choose>
 B B B B B  </xsl:for-each-group>
 B B B  </xsl:copy>
 B  </xsl:template>


-- Gerrit Imsieke GeschC$ftsfC<hrer / Managing Director le-tex publishing services GmbH Weissenfelser Str. 84, 04229 Leipzig, Germany Phone +49 341 355356 110, Fax +49 341 355356 510 gerrit.imsieke@xxxxxxxxx, http://www.le-tex.de

Registergericht / Commercial Register: Amtsgericht Leipzig
Registernummer / Registration Number: HRB 24930

GeschC$ftsfC<hrer / Managing Directors:
Gerrit Imsieke, Svea Jelonek, Thomas Schmidt

Current Thread