xsl-list
[Top] [All Lists]

[xsl] Sum one attribute while grouping by another

2008-07-24 11:07:32
How do I sum one attribute while grouping by another?

From examples online (including posts in this list) I'm pretty sure a
recursive template is necessary but I can't figure out how. Unfortunately, all the examples are too simple (e.g. increment counter with position()) or assume you can divide the data by elements. All my elements are the same.

For instance, I have the following XML data:

<food>
 <item type="fruit" name="apple" rotten="6" total="10"/>
 <item type="fruit" name="orange" rotten="2" total="10"/>
 <item type="fruit" name="pear" rotten="1" total="4"/>
 <item type="vegetable" name="carrot" rotten="0" total="5"/>
 <item type="vegetable" name="potato" rotten="1" total="2"/>
</food>

To which I apply a stylesheet to get a nice table output. I know how to get to overall sums, but I don't know how to get the group/inner sums (denoted by '?'):

type    name    rotten  total   percent
fruit
        apple   6       10      60
        orange  2       10      20
        pear    1       4       25
        total   ?       ?       ?
vegetable
        carrot  0       5       0
        potato  1       2       50
        total   ?       ?       ?
total           10      31      32.3

Here are some assumptions that can be made about the data:
* The items are guaranteed to be sorted by the "type" attribute.
* I don't know the possible values of "type" beforehand.
* Its format cannot be changed.

Also:
* I am using XSLT 1.0, but upgrading to 2.0 might be possible (I'm not sure).
* I am using python 2.4 with libxml2 and libxslt.

Here's the stylesheet I have now (that generated the above table):

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
        <xsl:template match="/">
   <html><body><table>
   <tr>
     <td>type</td>
     <td>name</td>
     <td>rotten</td>
     <td>total</td>
     <td>percent</td>
   </tr>

   <xsl:for-each select="//item">
     <xsl:if test="not(preceding-sibling::*[1]/@type=(_at_)type)">
       <tr><td><xsl:value-of select="@type"/></td></tr>
     </xsl:if>

     <tr>
       <td></td>
       <td><xsl:value-of select="@name"/></td>
       <td><xsl:value-of select="@rotten"/></td>
       <td><xsl:value-of select="@total"/></td>
<td><xsl:value-of select="format-number(@rotten div @total * 100,'##.#')"/></td>
     </tr>

     <xsl:if test="not(following-sibling::*[1]/@type=(_at_)type)">
       <tr>
         <td></td>
         <td>total</td>
         <td>?</td>
         <td>?</td>
         <td>?</td>
       </tr>
     </xsl:if>
   </xsl:for-each>

   <tr>
     <td>total</td>
     <td></td>
     <td><xsl:value-of select="sum(//item/@rotten)"/></td>
     <td><xsl:value-of select="sum(//item/@total)"/></td>
<td><xsl:value-of select="format-number(sum(//item/@rotten) div sum(//item/@total) * 100,'##.#')"/></td>
   </tr>
   </table></body></html>
        </xsl:template>
</xsl:stylesheet>

Thank you,
DB

--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--

<Prev in Thread] Current Thread [Next in Thread>
  • [xsl] Sum one attribute while grouping by another, DB <=