Re: [xsl] Grouping help

Subject: Re: [xsl] Grouping help
From: "Imsieke, Gerrit, le-tex gerrit.imsieke@xxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Sun, 24 Jul 2022 18:08:22 -0000
Hi Rick,

After more tinkering than I thought would be necessary, I came up with this solution:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
  xmlns:xs="http://www.w3.org/2001/XMLSchema";
  exclude-result-prefixes="xs"
  version="3.0">

<xsl:mode on-no-match="shallow-copy"/>

  <xsl:template match="/root">
    <task>
      <xsl:call-template name="group">
        <xsl:with-param name="elements" select="*" as="element(*)+"/>
      </xsl:call-template>
    </task>
  </xsl:template>

  <xsl:template name="group">
    <xsl:param name="elements" as="element(*)*"/>
    <xsl:variable name="min-level" as="xs:integer?"
      select="min($elements/@level) => xs:integer()" />
    <xsl:variable name="prelim" as="document-node()">
      <!-- wrap temporary results in a document node because otherwise
           there wouldn't be adjacency among the result elements -->
      <xsl:document>
        <xsl:for-each-group select="$elements"
          group-starting-with="*[@level = $min-level]">
          <xsl:choose>
            <!-- remember: the context item is the first item
                 in the current group -->
            <xsl:when test="exists(@level)">
              <xsl:apply-templates select="." mode="nest"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:apply-templates select="current-group()"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:for-each-group>
      </xsl:document>
    </xsl:variable>
    <xsl:for-each-group select="$prelim/*" group-adjacent="name()">
      <xsl:choose>
        <xsl:when test="starts-with(current-grouping-key(), 'list')">
          <!-- merge the many single-item lists that have been created
               in the first pass -->
          <xsl:copy>
            <xsl:sequence select="current-group()/*"/>
          </xsl:copy>
        </xsl:when>
        <xsl:otherwise>
          <xsl:sequence select="current-group()"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each-group>
  </xsl:template>

  <xsl:template match="item[@level = '2']" mode="nest">
    <pretopic lbl="{@number}">
      <title>
        <xsl:apply-templates/>
      </title>
      <xsl:call-template name="group">
        <xsl:with-param name="elements" select="tail(current-group())"/>
      </xsl:call-template>
    </pretopic>
  </xsl:template>

  <xsl:template match="item" mode="nest">
    <xsl:element name="list{@level - 2}">
      <xsl:apply-templates select="."/>
      <xsl:call-template name="group">
        <xsl:with-param name="elements" select="tail(current-group())"/>
      </xsl:call-template>
    </xsl:element>
  </xsl:template>

  <xsl:template match="item">
    <xsl:element name="l{@level - 2}item">
      <xsl:attribute name="lbl" select="@number"/>
      <xsl:apply-templates/>
    </xsl:element>
  </xsl:template>

</xsl:stylesheet>

In prose form:

'group' is a recursive template that will apply a grouping to its input elements that starts at the items with the lowest @level.

In the initial invocation, it will create pretopic elements from the @level=2 items. In each group, the first element will become the title and the remainder of the group will be the input for a nested call of the 'group' template.

For item[@level > 2], it will create <listX> elements, with X = @level - 2. Adjacent item[@level = '3'] elements will result in adjacent list1 elements, each of them having just one l1item child. The same for item[@level = '4']: They will result in list2 elements within a l1item,
but each list2 element will only hold a single l2item.


In order to merge the single-item result lists, the preliminary output will be grouped again, this time using group-adjacent by the name of the result elements. If the name starts with 'list' (list1, list2, ...), the single-item lists will be merged into a longer list with the same name (list1 etc.) that contains all the l1item (etc.) children of all adjacent single-item lists.

This second grouping will leave all other result elements (apart from the lists) unchanged.

The recursive grouping using the 'group' template will work for more levels than were present in your input.

Gerrit


On 22.07.2022 22:06, rick@xxxxxxxxxxxxxx wrote:
When I start a new group, I donbt get the rest of the items in the previous group.

*From:* rick@xxxxxxxxxxxxxx <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
*Sent:* Friday, July 22, 2022 2:21 PM
*To:* xsl-list@xxxxxxxxxxxxxxxxxxxxxx
*Subject:* Re: [xsl] Grouping help

I am sorry about that. Here is the desired output.

<?xml version="1.0" encoding="UTF-8"?>

<task>

B B <pretopic lbl="A.">

B B B B B <title>General</title>

B B B B B <list1>

B B B B B B B B <l1item lbl="(1)">This task gives...</l1item>

B B B B B B B B <list2>

B B B B B B B B B B B <l2item lbl="(a)">Replace the water...</l2item>

B B B B B B B B B B B <l2item lbl="(b)">Replace the barrier...</l2item>

B B B B B B B B B B B <l2item lbl="(c)">Replace the...</l2item>

B B B B B B B B </list2>

B B B B B B B B <l1item lbl="(2)">This task takes...</l1item>

B B B B B B B B <note type="note" position="1">NOTE:</note>

B B B B B B B B <note type="note" position="2">Refer to typical...</note>

B B B B B </list1>

B B </pretopic>

B B <pretopic lbl="B.">

B B B B B <title>References</title>

B B </pretopic>

B B <pretopic lbl="C.">

B B B B B <title>Tools/Equipment</title>

B B B B B <note type="note" position="1">NOTE:</note>

B B B B B <note type="note" position="2">When more than one...</note>

B B B B B <effectivity>Effective on:</effectivity>

B B B B B <effectivity>Effective on:</effectivity>

B B </pretopic>

B B <pretopic lbl="D.">

B B B B B <title>Consumable Materials</title>

B B </pretopic>

B B <pretopic lbl="E.">

B B B B B <title>Location Zones</title>

B B </pretopic>

B B <pretopic lbl="F.">

B B B B B <title>Procedure</title>

B B B B B <list1>

B B B B B B B B <l1item lbl="(1)">Do a check...</l1item>

B B B B B B B B <l1item lbl="(2)">Repair or replace...</l1item>

B B B B B B B B <l1item lbl="(3)">Do this task...</l1item>

B B B B B B B B <l1item lbl="(4)">Do a check...</l1item>

B B B B B B B B <l1item lbl="(5)">Replace the sealant...</l1item>

B B B B B B B B <l1item lbl="(6)">Do a check of...</l1item>

B B B B B B B B <list2>

B B B B B B B B B B B <l2item lbl="(a)">Replace the water...</l2item>

B B B B B B B B B B B <l2item lbl="(b)">Replace the barrier...</l2item>

B B B B B B B B B B B <l2item lbl="(c)">Replace the...</l2item>

B B B B B B B B </list2>

B B B B B B B B <l1item lbl="(7)">Assemble the...</l1item>

B B B B B B B B <l1item lbl="(8)">Seal all of the...</l1item>

B B B B B B B B <note type="caution" position="1">CAUTION:</note>

B B B B B B B B <note type="caution" position="2">MAKE SURE...</note>

B B B B B B B B <l1item lbl="(9)">Apply a layer of grease as follows: <para>Apply a layer of...</para></l1item>

B B B B B B B B <note type="note" position="1">NOTE:</note>

B B B B B B B B <note type="note" position="2">The grease can...</note>

B B B B B B B B <l1item lbl="(10)">Use the <b>vacuum cups</b> ...</l1item>

B B B B B </list1>

B B </pretopic>

</task>

XSL-List info and archive <http://www.mulberrytech.com/xsl/xsl-list>

EasyUnsubscribe <http://lists.mulberrytech.com/unsub/xsl-list/612310> (by email)

XSL-List info and archive <http://www.mulberrytech.com/xsl/xsl-list>

EasyUnsubscribe <http://lists.mulberrytech.com/unsub/xsl-list/612310> (by email)

XSL-List info and archive <http://www.mulberrytech.com/xsl/xsl-list>
EasyUnsubscribe <http://lists.mulberrytech.com/unsub/xsl-list/225679> (by email <>)

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