[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

RE: XSLT2: Clustering, or Grouping the groups

Subject: RE: XSLT2: Clustering, or Grouping the groups
From: "Michael Kay" <mhk@xxxxxxxxx>
Date: Tue, 25 May 2004 08:16:29 +0100
xslt2 for each group
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@xxxxxx] 
> Sent: 24 May 2004 22:52
> To: XSLT-List
> Subject:  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."

Current Thread

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2013 All Rights Reserved.