xsl-list
[Top] [All Lists]

Re: Problem with grouping multi level nodes

2004-03-16 23:29:49

      <name>Student 1</name>    
      <classes>            
         <class>            
            <title>soccer</title>        
            <category>sport</category>                   
         </class>            
         <class>            
            <title>football</title>        
            <category>sport</category>                   
         </class>            

So Student 1 has two class elements under classes, each of which
falls under category sport.

   <p>Student group by Category</p>
   <xsl:for-each select="/category[not(. = preceding::category)]">
      <p><xsl:value-of select="."/></p>

      <xsl:for-each select="key('categories',.)">
         <p><xsl:value-of select="../../name"/></p>
      </xsl:for-each>

   </xsl:for-each>

The inner for-each you specify selects all categories matching the current
category and then outputs the name. That means when category is 'sport',
Student 1 matches twice.

To solve the problem you posted, I found the techniques discussed in
http://www.jenitennison.com/xslt/grouping/index.html to be useful.
If you use the Muenchian technique discussed under that URL, you can
select the first occurance of each unique title, category, and class
with a unique title-category combination, and then apply templates to
the student/name element for each match:

<?xml version='1.0' encoding='ISO-8859-1'?>
<xsl:stylesheet
  xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
  version='1.0'>

  <xsl:key name='title' match='title' use='.'/>
  <xsl:key name='category' match='category' use='.'/>
  <xsl:key name='class' match='class' use='concat(./title, " - ", ./category)'/>

  <xsl:key name='by_title' match='student' use='./classes/class/title'/>
  <xsl:key name='by_category' match='student' use='./classes/class/category'/>

  <xsl:output method='text' indent='no'/>

  <xsl:template match="students">
    <xsl:text>&#10;Student group by title&#10;&#10;</xsl:text>
    <xsl:apply-templates select='./student/classes/class/title
       [generate-id(.)=generate-id(key("title", .))]'>
      <xsl:sort select="."/>
    </xsl:apply-templates>

    <xsl:text>&#10;Student group by category&#10;&#10;</xsl:text>
    <xsl:apply-templates select='./student/classes/class/category
        [generate-id(.)=generate-id(key("category", .))]'>
      <xsl:sort select="."/>
    </xsl:apply-templates>

    <xsl:text>&#10;Student group by title and category&#10;&#10;</xsl:text>
    <xsl:apply-templates select='./student/classes/class
        [generate-id(.)=generate-id(key("class", concat(./title, " - ", 
./category)))]'>
      <xsl:sort select="."/>
    </xsl:apply-templates>

  </xsl:template>

  <xsl:template match="title">
    <xsl:value-of select='.'/>
    <xsl:text>&#10;</xsl:text>
    <xsl:apply-templates select='key("by_title", .)/name'>
      <xsl:sort select='.'/>
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="category">
    <xsl:value-of select='.'/>
    <xsl:text>&#10;</xsl:text>
    <xsl:apply-templates select='key("by_category", .)/name'>
      <xsl:sort select='.'/>
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="class">
    <xsl:variable name='title_category' select='concat(./title, " - ", 
./category)'/>
    <xsl:value-of select='$title_category'/>
    <xsl:text>&#10;</xsl:text>
    <xsl:apply-templates select='key("class", $title_category)/../../name'>
      <xsl:sort select='.'/>
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match='name'>
    <xsl:text>&#09;</xsl:text>
    <xsl:value-of select='.'/>
    <xsl:text>&#10;</xsl:text>
  </xsl:template>

</xsl:stylesheet>

 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list



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