[xsl] Re: Constructing multi-level lists - any better than this?

Subject: [xsl] Re: Constructing multi-level lists - any better than this?
From: Michael Müller-Hillebrand <mmh@xxxxxxxxxxxxx>
Date: Wed, 19 Sep 2007 14:48:51 +0200
Andrew,

You're the man! Not only am I using Kernow all day for test-running
my stylesheet, your solution rocks.

Since the grouping needs only two modes, it is easy to
introduceboolean() in the group-adjacent attribute.

Another thing which I found being true very often: The shorter the
code, the more flexible its adaption to change requests. And I
noticed (poor me!) that the structure requirement of the target XML
is not

<!ELEMENT ul (li | ul)+>
<!ELEMENT li (p)+>

but

<!ELEMENT ul (li)+>
<!ELEMENT li (p, ul?)+>

[Previously I left out the <p> for clarity.]

Bottom line: It was acceptably easy to adapt your solution to this
changed requirement and during that process also using group-starting-
with:

<xsl:for-each-group select="*" group-adjacent="boolean(self::li1 or
self::li2)">
  <xsl:choose>
    <xsl:when test="current-grouping-key()">
      <ul level="1">
        <xsl:for-each-group select="current-group()" group-starting-
with="li1">
          <li tag="{name()}">
            <xsl:for-each-group select="current-group()" group-
adjacent="boolean(self::li1)">
              <xsl:choose>
                <xsl:when test="current-grouping-key()">
                  <xsl:apply-templates select="current-group()"/>
                </xsl:when>
                <xsl:otherwise>
                  <ul level="2">
                    <xsl:apply-templates select="current-group()"/>
                  </ul>
                </xsl:otherwise>
              </xsl:choose>
            </xsl:for-each-group>
          </li>
        </xsl:for-each-group>
      </ul>
    </xsl:when>
    <xsl:otherwise>
      <xsl:apply-templates select="current-group()"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:for-each-group>

The li1 and li2 need different templates then:

<xsl:template match="li1">
  <p><xsl:apply-templates/></p>
</xsl:template>

<xsl:template match="li2">
  <li tag="{name()}">
    <p><xsl:apply-templates/></p>
  </li>
</xsl:template>

Now I have to adapt this to my attribute driven real-world case with
the help of what I learned from Geert about xsl:function!

Thanks a lot to all!

- Michael M|ller-Hillebrand

Current Thread