Re: [xsl] grouping list items by attribute

Subject: Re: [xsl] grouping list items by attribute
From: Jon Gorman <jonathan.gorman@xxxxxxxxx>
Date: Wed, 5 Oct 2005 09:11:33 -0500
On 10/5/05, Lynn Alford <lynn.alford@xxxxxxxxxx> wrote:
> I'm very close to the results I'd like but am hoping for a few pointers to
> finish this part of the transformation off.  The answer has to be used by
> Xalan - so it must be an xslt1 solution.

I can't give a huge amount of pointers at the moment, but I think
you're on the right track.

One quick note before I begin.  Your xslt is a bit verbose, and I'm
quite sure that following-sibling::*[1][self::fl:tx.li]"  could be
simply following-sibling::tx.li[1].

Let me just summarize my understanding of your xslt.  You're stepping
through the list one item at a time.  If the following sibling has the
same level, just apply the "in-list" template to it.   If the
following sibling has a greater level, apply the list to it.  The
problem of course being is that you are dealing with nested  lists,
and using th is algorithm you'll end up having problems when the
levels start going down.

So what you need to do is when the levels increase is split it...apply
the new list template to all the following-siblings of the increased
level and apply the next in-list to the first following-sibling of the
same level.  Probably the easiest way to do this is alter your
templates so they pass in nodesets via with-param a

ie something like (not tested, and just here to provide some hints )

<xsl:template name="processList">
<xsl:param name="nodes" />
<!-- some of your other stuff  and probably need a for loop that
iterates over all the nodes-->

      <xsl:choose>
        <xsl:when test="@level &gt;= following-sibling::*[1]/@level">
                     <xsl:apply-templates
> select="$nodes/following-sibling::tx.li[1]" mode="in-list"/>
             <xsl:call-template name="processList">

        </xsl:when>
        <xsl:when test="@level &lt; following-sibling::*[1]/@level">
          <xsl:apply-templates
 select="following-sibling::tx.li[1][self::fl:tx.li]" mode="new-list"/>

        </xsl:when>



It's a little tricky, but that way you'll keep encapsulating all the
"higher" levels in new lists while keeping those of the current level
in the same list.  Thanks to recursion this just cycles on until we
run out of nested lists.



Jon Gorman

 the xsl is currently
>
> <?xml version="1.0" encoding="UTF-8"?>
> <xsl:stylesheet version="1.0"
> xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
> exclude-result-prefixes="#default fl"
> xmlns:fl="http://www.outsideinsdk.com/xmlns/flexiondoc5_1";>
>    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
>    <xsl:preserve-space elements="fl:tx.p"/>
>    <xsl:template match="/">
>      <out>
>        <xsl:apply-templates/>
>      </out>
>    </xsl:template>
>
>    <xsl:template match="fl:tx.p">
>      <para>
>        <xsl:value-of select="."/>
>      </para>
>    </xsl:template>
>    <xsl:template match="fl:tx.li"/>
>    <xsl:template
> match="fl:tx.li[not(preceding-sibling::*[1][self::fl:tx.li])]">
>      <xsl:apply-templates select="." mode="new-list"/>
>    </xsl:template>
>    <xsl:template match="fl:tx.li" mode="new-list">
>      <xsl:choose>
>        <xsl:when test="contains(@number,'.') or contains(@number,')')">
>          <orderedlist>
>            <xsl:apply-templates select="." mode="in-list"/>
>          </orderedlist>
>        </xsl:when>
>        <xsl:otherwise>
>          <itemizedlist>
>            <xsl:apply-templates select="." mode="in-list"/>
>          </itemizedlist>
>        </xsl:otherwise>
>      </xsl:choose>
>    </xsl:template>
>    <xsl:template match="fl:tx.li" mode="in-list">
>      <listitem level="{@level}" number="{@number}">
>        <xsl:apply-templates select="child::*"/>
>      </listitem>
>      <xsl:choose>
>        <xsl:when test="@level &gt;= following-sibling::*[1]/@level">
>          <xsl:apply-templates
> select="following-sibling::*[1][self::fl:tx.li]" mode="in-list"/>
>        </xsl:when>
>        <xsl:when test="@level &lt; following-sibling::*[1]/@level">
>          <xsl:apply-templates
> select="following-sibling::*[1][self::fl:tx.li]" mode="new-list"/>
>        </xsl:when>
>
>      </xsl:choose>
>    </xsl:template>
> </xsl:stylesheet>
>
> Current output is
>
> <?xml version="1.0" encoding="UTF-8"?>
> <out>
>          <para>List test</para>
>          <orderedlist>
>                  <listitem level="0" number="1.  ">
>                          <para>Ordered - list item</para>
>                  </listitem>
>                  <orderedlist>
>                          <listitem level="1" number="a.  ">
>                                  <para>Nested list item</para>
>                          </listitem>
>                          <listitem level="1" number="b.  ">
>                                  <para>Nested list item</para>
>                          </listitem>
>                          <itemizedlist>
>                                  <listitem level="2" number="o?=   ">
>                                          <para>Nested nested list item</para>
>                                  </listitem>
>                                  <listitem level="2" number="o?=   ">
>                                          <para>And yet another</para>
>                                  </listitem>
>                                  <listitem level="0" number="2.  ">
>                                          <para>Ordered list item</para>
>                                  </listitem>
>                                  <listitem level="0" number="3.  ">
>                                          <para>Ordered list item</para>
>                                  </listitem>
>                          </itemizedlist>
>                  </orderedlist>
>          </orderedlist>
> </out>
>
> Desired output would mean
>
> <?xml version="1.0" encoding="UTF-8"?>
> <out>
>          <para>List test</para>
>          <orderedlist>
>                  <listitem level="0" number="1.  ">
>                          <para>Ordered - list item</para>
>                  </listitem>
>                  <orderedlist>
>                          <listitem level="1" number="a.  ">
>                                  <para>Nested list item</para>
>                          </listitem>
>                          <listitem level="1" number="b.  ">
>                                  <para>Nested list item</para>
>                          </listitem>
>                          <itemizedlist>
>                                  <listitem level="2" number="o?=   ">
>                                          <para>Nested nested list item</para>
>                                  </listitem>
>                                  <listitem level="2" number="o?=   ">
>                                          <para>And yet another</para>
>                                  </listitem>
>                                       </itemizedlist>
>                          </orderedlist>
>                  <listitem level="0" number="2.  ">
>                          <para>Ordered list item</para>
>                  </listitem>
>                  <listitem level="0" number="3.  ">
>                          <para>Ordered list item</para>
>                  </listitem>
>          </orderedlist>
> </out>

Current Thread