Re: [xsl] XSLT 1.0: Grouping Adjacent Elements in Embedded Lists

Subject: Re: [xsl] XSLT 1.0: Grouping Adjacent Elements in Embedded Lists
From: Geert Josten <Geert.Josten@xxxxxxxxxxx>
Date: Fri, 05 Nov 2004 18:57:04 +0100
Hi Joe,

Sorry to do it this way, but it was easier for me to rewrite the script than to debug it. I have once build a stylesheet that converts mapping rules into a xsl. This mapping definition contained a command to gather sequences of elements into a wrapper element. It is related to the sort grouping problem, but that doesn't help you if you have to interfere the wrapping at the encounter of a certain element and continue it afterwards.

Anyhow, I conceived some nice methods to just do the trick you are trying to do. In your case the code would look like the following. Note that I have wrapped you initial dataset in a DATA element. Msxsl seems to give the correct output.

Grtz,
Geert

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>

<!--+ ==============================================================
    | output
    +-->

<xsl:output method="xml" indent="yes" encoding="utf-8" />

<!--+ ==============================================================
    | main group
    +-->

  <xsl:template match="DATA">
    <html>
      <xsl:apply-templates select="node()" />
    </html>
  </xsl:template>

  <xsl:template match="OL_LI">
    <!-- jump to start-top-level-list group to start top level nesting -->
    <xsl:apply-templates select="." mode="start-top-level-list"/>
  </xsl:template>

  <xsl:template match="EM_OL_LI">
    <!-- suppress at this level, you are outside the top-level wrappers! -->
  </xsl:template>

<!--+ ==============================================================
    | group top-level-list
    +-->

  <xsl:template match="@*|node()" mode="start-top-level-list">
    <!-- jump back to main group, if nothing else matches! -->
    <xsl:apply-templates select="." />
  </xsl:template>

  <xsl:template match="OL_LI" mode="start-top-level-list">
    <p>
       <ol>
          <li><xsl:apply-templates /></li>
          <!-- jump to continue-top-level-list to find out whether sub level list should be started -->
          <xsl:apply-templates select="following-sibling::node()[1]" mode="continue-top-level-list"/>
       </ol>
    </p>
  </xsl:template>

  <xsl:template match="EM_OL_LI" mode="start-top-level-list">
    <!-- suppress at this level, you are outside the top-level wrappers! -->
  </xsl:template>

<!--+ ==============================================================
    | group continue-top-level-list
    +-->

<xsl:template match="@*|node()" mode="continue-top-level-list">
<!-- skip attributes, text, comments and pi's -->
<!-- Note: you might want to copy these with xsl:copy-of select="." or call an other template group, perhaps the main group -->
<xsl:apply-templates select="following-sibling::node()[1]" mode="continue-top-level-list"/>
</xsl:template>


  <xsl:template match="*" mode="continue-top-level-list">
    <!-- end continuation as an element is encountered that doesn't belong in this group -->
  </xsl:template>

  <xsl:template match="EM_OL_LI" mode="continue-top-level-list">
    <!-- jump to top-level-list group to start top level nesting -->
    <xsl:apply-templates select="." mode="start-sub-level-list"/>
    <!-- this also stops continuation in this group, as the sub-level-list continues itself -->
  </xsl:template>

<!--+ ==============================================================
    | group start-sub-level-list
    +-->

  <xsl:template match="@*|node()" mode="start-sub-level-list">
    <!-- jump back to continue-top-level-list, if nothing else matches! -->
    <xsl:apply-templates select="." mode="continue-top-level-list" />
  </xsl:template>

  <xsl:template match="EM_OL_LI" mode="start-sub-level-list">
    <p>
       <ol>
          <li><xsl:apply-templates /></li>
          <xsl:apply-templates select="following-sibling::node()[1]" mode="continue-sub-level-list"/>
       </ol>
    </p>
  </xsl:template>

<!--+ ==============================================================
    | group continue-sub-level-list
    +-->

<xsl:template match="@*|node()" mode="continue-sub-level-list">
<!-- skip attributes, text, comments and pi's -->
<!-- Note: you might want to copy these with xsl:copy-of select="." or call an other template group, perhaps the main group -->
<xsl:apply-templates select="following-sibling::node()[1]" mode="continue-sub-level-list"/>
</xsl:template>


  <xsl:template match="*" mode="continue-sub-level-list">
    <!-- end continuation as an element is encountered that doesn't belong in this group -->
  </xsl:template>

  <xsl:template match="EM_OL_LI" mode="continue-sub-level-list">
    <!-- output sub level list item -->
    <li><xsl:apply-templates /></li>
    <!-- continue with following EM_OM_LI elements -->
    <xsl:apply-templates select="following-sibling::node()[1]" mode="continue-sub-level-list"/>
  </xsl:template>

</xsl:stylesheet>

Current Thread