[XSL-LIST Mailing List Archive Home] [By Thread] [By Date]

RE: [xsl] both sorting and grouping set of nodes


Subject: RE: [xsl] both sorting and grouping set of nodes
From: "Michael Kay" <mike@xxxxxxxxxxxx>
Date: Thu, 3 Dec 2009 09:28:20 -0000

There's an example showing how to do this on p343 of my book (4e). I think
it needs a two-phase solution:

<xsl:template match="towns">
<xsl:variable name="sorted-towns" as="element()*">
  <xsl:perform-sort select="town">
     <xsl:sort/>
  </xsl:perform-sort>
</xsl:variable>
<table>
  <xsl:for-each-group select="$sorted-towns" 
         group-by="position() mod (last() idiv $cols)">
  <tr>
   <xsl:for-each select="current-group()">
   <td>
      <xsl:value-of select="."/>
   </td>
   </xsl:for-each>
  </tr>
  </xsl:for-each-group>

</table>
</xsl:template> 


Regards,

Michael Kay
http://www.saxonica.com/
http://twitter.com/michaelhkay 

> -----Original Message-----
> From: Syd Bauman [mailto:Syd_Bauman@xxxxxxxxx] 
> Sent: 03 December 2009 03:17
> To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> Subject: [xsl] both sorting and grouping set of nodes
> 
> Warning: intended to be read in a monospaced typeface.
> 
> This may abe a FAQ, but if so, I didn't find it on D. 
> Pawson's FAQ pages.
> 
> The basic idea is that I want to extract a sizeable set of 
> nodes from a file, sort them, and spit out the output in a 
> 4-column XHTML table.
> 
> So let's pretend I have an input document with a few hundred 
> <name> elements. And presume the content thereof is aready in 
> the desired format (e.g., "Surname, Forename" -- it's not, 
> but let's start with the easy case). I know how to spit out a 
> sorted list of them:
>    <ul>
>      <xsl:for-each select="//name">
>        <xsl:sort select="normalize-space(.)"/>
>        <li><xsl:value-of select="normalize-space(.)"/></li>
>      </xsl:for-each>
>    </ul>
> 
> Or, a bit more robustly:
>    <ul>
>      <xsl:apply-templates select="//name">
>        <xsl:sort select="normalize-space(.)"/>
>      </xsl:apply-templates>
>    </ul>
>    ...
>    <xsl:template match="name">
>      <li><xsl:value-of select="normalize-space(.)"/></li>
>    </xsl:template>
> 
> And I've figured out a way to spit out a 4-column table of 
> them (reading down), although I bet folks on this list could 
> demonstrate a better method:
>    <table border="1">
>      <xsl:variable name="Q" select="ceiling( count( //name ) 
> div 4 )"/>
>      <xsl:for-each select="//name[ position() &lt;= $Q]">
>        <xsl:variable name="Q1" select="position() + (1 * $Q)"/>
>        <xsl:variable name="Q2" select="position() + (2 * $Q)"/>
>        <xsl:variable name="Q3" select="position() + (3 * $Q)"/>
>        <tr>
>          <td><xsl:value-of select="normalize-space(.)"/></td>
>          <td><xsl:value-of select="normalize-space( /*//name[ 
> $Q1] )"/></td>
>          <td><xsl:value-of select="normalize-space( /*//name[ 
> $Q2] )"/></td>
>          <td><xsl:value-of select="normalize-space( /*//name[ 
> $Q3] )"/></td>
>        </tr>
>      </xsl:for-each>
>    </table>
> 
> But how do I do both at once, i.e. generate a 4-column table (read
> down) of *sorted* names? E.g. something like either
>   Alex       Gaston      Lisa        Richard     
>   Bonnie     Hermine     Matthew     Shary       
>   Colin      Igor        Nicole      Tomas       
>   Danielle   Julia       Otto        Virginie    
>   Earl       Karl        Paula       Walter      
>   Fiona
> or
>   Alex       Gaston      Matthew     Tomas
>   Bonnie     Hermine     Nicole      Virginie
>   Colin      Igor        Otto        Walter
>   Danielle   Julia       Paula   
>   Earl       Karl        Richard         
>   Fiona      Lisa        Shary           
> 
> As recently noted on this list, XPath 2 doesn't have a sort() 
> function. I'm betting if I knew where to look in the 
> reference guides on my shelf, this isn't too hard. But I'm 
> really not sure how to get started. Fancy grouping? Sequences? Sigh.
> 
> Note that for this particular application, thinking of the 
> things to be sorted as a set of strings is fine. But one can 
> imangine wanting to the same thing with nodes that are more 
> complex. In any case, Thanks in advance.
> 
> Appendix 1
> -------- -
> Enormously simplified input for testing. 2 points to she who 
> first posts what this list of names is.
> 
> <?xml version="1.0" encoding="UTF-8"?>
> <names>
>   <name>Julia</name>
>   <name>Virginie</name>
>   <name>Bonnie</name>
>   <name>Paula</name>
>   <name>Lisa</name>
>   <name>Danielle</name>
>   <name>Fiona</name>
>   <name>Nicole</name>
>   <name>Alex</name>
>   <name>Shary</name>
>   <name>Earl</name>
>   <name>Gaston</name>
>   <name>Colin</name>
>   <name>Matthew</name>
>   <name>Hermine</name>
>   <name>Igor</name>
>   <name>Karl</name>
>   <name>Otto</name>
>   <name>Richard</name>
>   <name>Tomas</name>
>   <name>Walter</name>
> </names>


Current Thread
Keywords