Re: [xsl] Making a Table of Alphabetized Strings grouped by First Letter

Subject: Re: [xsl] Making a Table of Alphabetized Strings grouped by First Letter
From: Joerg Pietschmann <joerg.pietschmann@xxxxxx>
Date: Thu, 31 Jan 2002 17:05:51 +0100
Elizabeth Barham <soggytrousers@xxxxxxxxx> wrote:
[about a grouping problem]
Here is a pure XSLT 1.0 solution. It's somewhat convoluted, a
solution in XSLT 2.0 or using xx:node-set() could get rid
of recursion and the Piez-Method for simulating iteration
and would therefore probably easier to read.
I used a simplified XML
  <?xml version="1.0"?>
  <counties>
    <county>Anderson</county>
    <county>Bailey</county>
    ...
  </counties>
in order to shorten the XPath, they are already unwieldy enough.

The core is the recursive template which accumulates both county
elements with all different initials in "$startlist" and the
maximum number of counties starting with a particular initial
in "$maxcount".

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
  <xsl:output method="html"/>

  <xsl:key name="county-initial" match="county" use="substring(.,1,1)"/>
  
  <xsl:template match="counties">
    <table>
      <xsl:call-template name="accumulate">
        <xsl:with-param name="countylist" select="county"/>
        <xsl:with-param name="startlist" select="/.."/>
        <xsl:with-param name="maxcount" select="0"/>
      </xsl:call-template>
    </table>
  </xsl:template>

  <xsl:template name="accumulate">
    <xsl:param name="countylist"/>
    <xsl:param name="startlist"/>
    <xsl:param name="maxcount"/>
    <xsl:choose>
      <xsl:when test="$countylist">
        <xsl:variable name="initial" select="substring($countylist[1],1,1)"/>
        <xsl:variable name="currentcount"
          select="count(key('county-initial',$initial))"/>
        <xsl:choose>
          <xsl:when test="$currentcount &gt; $maxcount">
            <xsl:call-template name="accumulate">
              <xsl:with-param name="countylist" select="$countylist[not(substring(.,1,1)=$initial)]"/>
              <xsl:with-param name="startlist" select="$startlist|$countylist[1]"/>
              <xsl:with-param name="maxcount" select="$currentcount"/>
            </xsl:call-template>
          </xsl:when>
          <xsl:otherwise>
            <xsl:call-template name="accumulate">
              <xsl:with-param name="countylist" select="$countylist[not(substring(.,1,1)=$initial)]"/>
              <xsl:with-param name="startlist" select="$startlist|$countylist[1]"/>
              <xsl:with-param name="maxcount" select="$maxcount"/>
            </xsl:call-template>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:when>
      <xsl:otherwise>
        <!-- use Wendell Pietz' method for iterating over 1..$maxcount -->
        <xsl:for-each select="(//node())[position() &lt;= $maxcount]">
          <xsl:variable name="index" select="position()"/>
          <tr>
            <xsl:for-each select="$startlist">
              <xsl:for-each select="key('county-initial',substring(.,1,1))[$index]">
                <td><xsl:value-of select="."/></td>
              </xsl:for-each>
            </xsl:for-each>
          </tr>
        </xsl:for-each>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

As the lists auto documentation demon seems to be down, ask
again if something is unclear or too tricky.

HTH
J.Pietschmann

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


Current Thread