[xsl] Calculating cumulative values - another call for help

Subject: [xsl] Calculating cumulative values - another call for help
From: "Simon Shutter" <simon@xxxxxxxxxxx>
Date: Wed, 29 Aug 2007 00:05:11 -0700
Dear Experts,

I've been aggregating numbers in XSLT 1.0 using the preceding-sibling:: axis
for nodes with the same parent.  I now need to aggregate all the values that
precede the context node, even if they have different parents.  For this I
added another attribute using the preceding:: axis (see XSLT 1.0 Stylesheet
below).  Unfortunately, the transform is starting to groan under the weight
of all these O(n^2) operations.  I have revisited an earlier solution
suggested by Dimitre Novatchev (see XSLT 2.0 Stylesheet below) that uses
FXSL.  However, I'm not clear how I can adapt it to meet the new
requirements.  Specifically, I would like to:

a) generate attribute y3 that is a cumulative value based on all preceding
<point> elements
b) copy y1 from the input to the output

Sincerely, Simon


---------------------------------------------
XSLT 2.0 Stylesheet 
---------------------------------------------
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
 xmlns:f="http://fxsl.sf.net/";
 exclude-result-prefixes="f">
  <xsl:import href="fxsl-xslt2/f/func-scanlDVC.xsl"/>
  <xsl:import href="fxsl-xslt2/f/func-Operators.xsl"/>

  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="set">
    <xsl:copy>
      <xsl:copy-of select="@*"/>
      <xsl:for-each-group select="point" group-by="@x">
         <xsl:sort select="current-grouping-key()" data-type="number"/>
         <xsl:for-each select="f:scanl1(f:add(), current-group()/@y1)">
            <point x="{current-group()[1]/@x}" y2="{.}"/>
         </xsl:for-each>
      </xsl:for-each-group>
    </xsl:copy>
 </xsl:template>

</xsl:stylesheet>


---------------------------------------------
XSLT 1.0 Stylesheet
---------------------------------------------
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>

<xsl:template match="node()|@*">
  <xsl:copy>
    <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="point">
 <xsl:copy>
   <xsl:copy-of select="@*"/>
   <xsl:attribute name="y2">
     <xsl:value-of select="sum(./@y1|preceding-sibling::point[@x =
current()/@x]/@y1)"/>
   </xsl:attribute>
   <xsl:attribute name="y3">
     <xsl:value-of select="sum(./@y1|preceding::point[@x =
current()/@x]/@y1)"/>
   </xsl:attribute>
 </xsl:copy>
</xsl:template>

</xsl:stylesheet>

---------------------------------------------
Input
---------------------------------------------

<root id="theroot">
  <set id="1">
    <point x="1" y1="2" />
    <point x="1" y1="3" />
    <point x="1" y1="0" />
    <point x="1" y1="2" />
    <point x="1" y1="2" />
    <point x="2" y1="3" />
    <point x="2" y1="0" />
    <point x="2" y1="2" />
    <point x="3" y1="2" />
    <point x="3" y1="3" />
    <point x="3" y1="1" />
    <point x="3" y1="2" />
    <point x="3" y1="2" />
  </set>
  <set id="2">
    <point x="1" y1="2" />
    <point x="1" y1="3" />
    <point x="1" y1="0" />
    <point x="1" y1="2" />
    <point x="2" y1="2" />
    <point x="3" y1="2" />
    <point x="3" y1="2" />
    <point x="3" y1="2" />
  </set>
  <set id="n">
    <point x="1" y1="2" />
    <point x="1" y1="3" />
    <point x="1" y1="2" />
    <point x="2" y1="3" />
    <point x="2" y1="0" />
    <point x="2" y1="2" />
    <point x="3" y1="3" />
  </set>
</root>

---------------------------------------------
Desired Output
---------------------------------------------

<root id="theroot">
  <set id="1">
    <point x="1" y1="2" y2="2" y3="2"/>
    <point x="1" y1="3" y2="5" y3="5"/>
    <point x="1" y1="0" y2="5" y3="5"/>
    <point x="1" y1="2" y2="7" y3="7"/>
    <point x="1" y1="2" y2="9" y3="9"/>
    <point x="2" y1="3" y2="3" y3="3"/>
    <point x="2" y1="0" y2="3" y3="3"/>
    <point x="2" y1="2" y2="5" y3="5"/>
    <point x="3" y1="2" y2="2" y3="2"/>
    <point x="3" y1="3" y2="5" y3="5"/>
    <point x="3" y1="1" y2="6" y3="6"/>
    <point x="3" y1="2" y2="8" y3="8"/>
    <point x="3" y1="2" y2="10" y3="10"/>
  </set>
  <set id="2">
    <point x="1" y1="2" y2="2" y3="11"/>
    <point x="1" y1="3" y2="5" y3="14"/>
    <point x="1" y1="0" y2="5" y3="14"/>
    <point x="1" y1="2" y2="7" y3="16"/>
    <point x="2" y1="2" y2="2" y3="7"/>
    <point x="3" y1="2" y2="2" y3="12"/>
    <point x="3" y1="2" y2="4" y3="14"/>
    <point x="3" y1="2" y2="6" y3="16"/>
  </set>
  <set id="n">
    <point x="1" y1="2" y2="2" y3="18"/>
    <point x="1" y1="3" y2="5" y3="21"/>
    <point x="1" y1="2" y2="7" y3="23"/>
    <point x="2" y1="3" y2="3" y3="10"/>
    <point x="2" y1="0" y2="3" y3="10"/>
    <point x="2" y1="2" y2="5" y3="12"/>
    <point x="3" y1="3" y2="3" y3="19"/>
  </set>
</root>

Current Thread