xsl-list
[Top] [All Lists]

RE: XSLT2: Clustering, or Grouping the groups

2004-05-25 00:16:29
I think that when you need to do two levels of grouping like this, it is
usually easier to do it top-down: that is, do the outer level first. Doing
it bottom-up as you are attempting also works, but it requires two passes
over the data.

The top-down solution (untested) looks something like this:

<xsl:for-each-group select="bar" group-adjacent="exists(@baz)">
  <xsl:choose>
  <xsl:when test="exists(@baz)">
    <list>
      <xsl:for-each-group select="current-group() group-adjacent="@baz">
         <list-item>
            <xsl:copy-of select="current-group()" />
         </list-item>
      </xsl:for-each-group>
    </list>
  </xsl:when>
  <xsl:otherwise>
      <xsl:copy-of select="current-group()"/>
  </xsl:otherwise>
  </xsl:choose>
</xsl:for-each-group>


-----Original Message-----
From: A. Pagaltzis [mailto:pagaltzis(_at_)gmx(_dot_)de] 
Sent: 24 May 2004 22:52
To: XSLT-List
Subject: [xsl] XSLT2: Clustering, or Grouping the groups

Hi all,

I am using XSLT2 as implemented by Saxon 7.9.1 to group a flat
structure. What I start out with is something like

    <foo>
        <bar baz="1" />
        <bar baz="2" />
        <bar baz="2" />
        <bar />
        <bar baz="1" />
        <bar baz="1" />
        <bar />
    </foo>

Now I need to put these bars in a list. The first step is easy
enough (I'm only paraphrasing; excuse any syntax errors please):

    <xsl:for-each-group select="bar" group-adjacent="@baz">
        <xsl:choose>
            <xsl:when test="@baz">
                <list-item>
                    <xsl:copy-of select="current-group()" />
                </list-item>
            </xsl:when>
            <xsl:otherwise>
                <xsl:copy-of select="current-group()" />
            </xsl:otherwise>
        </xsl:choose>
    </xsl:for-each-group>

Now what I get looks like this:

    <foo>
        <list-item>
            <bar baz="1" />
        </list-item>
        <list-item>
            <bar baz="2" />
            <bar baz="2" />
        </list-item>
        <bar />
        <list-item>
            <bar baz="1" />
            <bar baz="1" />
        </list-item>
        <bar />
    </foo>

This is all well and good, but now I need to get to

    <foo>
        <list>
            <list-item>
                <bar baz="1" />
            </list-item>
            <list-item>
                <bar baz="2" />
                <bar baz="2" />
            </list-item>
        </list>
        <bar />
        <list>
            <list-item>
                <bar baz="1" />
                <bar baz="1" />
            </list-item>
        </list>
        <bar />
    </foo>

The only way I've succeeded in doing this was by two separate
stylesheets (where the second is pretty much a copy of the first,
except for different conditions and element names), which is
suboptimal.

I'd like to do this in a single step. I tried assigning the
output to a variable and processing it afterwards using something
like

    <xsl:variable name="list">
        <xsl:for-each-group select="bar" group-adjacent="@baz">
            <xsl:choose>
                <xsl:when test="@baz">
                    <list-item>
                        <xsl:copy-of select="current-group()" />
                    </list-item>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:copy-of select="current-group()" />
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each-group>
    </xsl:variable>
    <xsl:for-each-group select="$list" 

Your mistake here is that $list is a document node at the root of a
temporary tree: it is a sequence of length one, so using it as the grouping
population is not going to do much good. You should either select the
children of $list (which will include <list-item> and <baz> elements), or
you should declare the variable as a sequence of elements, by writing
<xsl:variable name="list" as="element()*">, in which case the document node
will not be constructed.

Michael Kay


group-adjacent="boolean(self::list-item)">
        <xsl:choose>
            <xsl:when test="   SOME-TEST-HERE()   "> <!-- KEY BIT -->
                <list-item>
                    <xsl:copy-of select="current-group()" />
                </list-item>
            </xsl:when>
            <xsl:otherwise>
                <xsl:copy-of select="current-group()" />
            </xsl:otherwise>
        </xsl:choose>
    </xsl:for-each-group>

Unfortunately, both what the context node is as well as the value
of current-group() at the point of SOME-TEST-HERE() seem to defy
all reason or reasonable expectation in such a way that I can't
figure out how to get the desired result.

Uh.. help?

-- 
Thanks muchly in advance,
Aristotle
 
"If you can't laugh at yourself, you don't take life 
seriously enough."

--+------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: 
<mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--+--





<Prev in Thread] Current Thread [Next in Thread>