[xsl] XSLT 1.0 Muenchian Grouping

Subject: [xsl] XSLT 1.0 Muenchian Grouping
From: "Steve Sze" <steveyksze@xxxxxxxxx>
Date: Sat, 15 Jul 2006 17:01:45 -0400
Hi Mukul, Mike, Spencer, David & Wendell

Yes, forgot to point out that Im using XSLT 1.0.  Mukul, based on the
Muenchian method, your code works well.  The explanation below is
super!  Based on everyone's explanation, I did approach this problem
with the wrong method.  I approach this problem with my Java
experience.  I guess Ive rely too much on Vectors & Arrays.

Thank You All!!!!
Steve

======================================================

- Show quoted text -

Hi Steve,
As Mike pointed out, this problem is best solved using Muenchian
grouping method, if you are using XSLT 1.0.

Here is a XSLT 1.0 solution based on Muenchian method:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>

<xsl:output method="html" indent="yes" />

<xsl:key name="by-country" match="entry" use="country" />

<xsl:template match="/report">
<html>
  <head>
    <title/>
  </head>
  <body>
    <table border="1">
      <xsl:for-each select="//entry[generate-id() =
generate-id(key('by-country', country)[1])]">
        <tr>
          <td><xsl:value-of select="country" /></td>
        </tr>
        <tr>
          <td>Group</td>
          <td>Name</td>
          <td>id</td>
        </tr>
        <xsl:for-each select="key('by-country', country)">
          <tr>
            <td><xsl:value-of select="../@type" /></td>
            <td><xsl:value-of select="name" /></td>
            <td><xsl:value-of select="id" /></td>
          </tr>
        </xsl:for-each>
      </xsl:for-each>
    </table>
  </body>
</html>
</xsl:template>

</xsl:stylesheet>

Regards,
Mukul

http://gandhimukul.tripod.com/


=============================================================



This is a classic grouping problem which is best tackled using xsl:for-each-group in XSLT 2.0, or Muenchian grouping (see http://www.jenitennison.com/xslt/grouping) in 1.0. The 2.0 solution is:

<xsl:for-each-group select="//entry" group-adjacent="country">
 <h2><xsl:value-of select="current-grouping-key()"/></h2>
 <table>
 <thead>...</thead>
 <tbody>
   <xsl:for-each select="current-group()">
     <tr>
      <td><xsl:value-of select="../@type"/></td>
      <td><xsl:value-of select="name"/></td>
      <td><xsl:value-of select="id"/></td>

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


=============================================================



Others have given solutions but let me just observe (given a recent thread about mutable variables) that the solutions follow the natural human language description rather than a solution that you'd program in an imperative programming language.

If you were describing the problem to a person you'd say that you want
to group the items by country and put a country heading at the top of
each group.

You wouldn't (or at least I wouldn't) introduce the notion of state and
some temporary variable holding the last seen country and say that for
each item you need to compare the current country with the value of the
variable stored at the last item.

The human-oriented description does not introduce any variables at all,
and the XSLT solutions typically don't use any variables either.
This is almost always the case when someone more familiar with
imperative programming languages has problems with the fact that xsl
variables "don't change". Usually it's not that you don't need to change
the value of a variable, it's that you don't need a variable at all.

David


=============================================================



Right. And explaining how to do that, you wouldn't say "pick up the items one at a time and if you've already done one with that country, skip it", you'd say "pick up one from each country and with it...", and if someone asked "okay which one" you'd say "it doesn't matter but if you really need me to say, the first one will do".

Thus the declarative approach also allows the implementor to optimize
where convenient, rather than fussing over details that don't really
matter to the solution.

Cheers,
Wendell

Current Thread