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

[xsl] both sorting and grouping set of nodes


Subject: [xsl] both sorting and grouping set of nodes
From: Syd Bauman <Syd_Bauman@xxxxxxxxx>
Date: Wed, 02 Dec 2009 22:17:22 -0500

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