xsl-list
[Top] [All Lists]

Re: Re: Re: How to Calculate Running Total using Variable within FOR-LOOP?

2003-12-07 22:42:25
Hi Bill,

You need just scanl (scanl1 is a variation of scanl which supposes that the
provided list is non-empty (there is at least one element in the list)).

If you're interested in this topic downloading FXSL will be the right thing
to do.

As it happens, the scanl template does not use any other template from FXSL.
Here's its code:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
xmlns:ext="http://exslt.org/common";
exclude-result-prefixes="xsl ext"

  <xsl:template name="scanl">
    <xsl:param name="pFun" select="/.."/>
    <xsl:param name="pQ0" select="/.."/>
    <xsl:param name="pList" select="/.."/>
    <xsl:param name="pElName" select="'el'"/>
    <xsl:param name="pStarting" select="1"/>

    <xsl:variable name="vLength" select="count($pList)"/>

    <xsl:choose>
      <xsl:when test="$vLength > 1">
        <xsl:variable name="vHalf" select="floor($vLength div 2)"/>

        <xsl:variable name="vrtfResult1">
        <xsl:call-template name="scanl">
        <xsl:with-param name="pFun" select="$pFun"/>
        <xsl:with-param name="pQ0" select="$pQ0" />
        <xsl:with-param name="pList" select="$pList[position() &lt;=
$vHalf]"/>
        <xsl:with-param name="pElName" select="$pElName"/>
            <xsl:with-param name="pStarting" select="$pStarting"/>
        </xsl:call-template>
       </xsl:variable>

       <xsl:variable name="vResult1" select="ext:node-set($vrtfResult1)/*"/>

       <xsl:copy-of select="$vResult1"/>

       <xsl:call-template name="scanl">
       <xsl:with-param name="pFun" select="$pFun"/>
       <xsl:with-param name="pQ0" select="$vResult1[last()]" />
       <xsl:with-param name="pList" select="$pList[position() > $vHalf]"/>
       <xsl:with-param name="pElName" select="$pElName"/>
          <xsl:with-param name="pStarting" select="0"/>
       </xsl:call-template>
      </xsl:when>

      <xsl:otherwise>
      <xsl:if test="$pStarting">
       <xsl:element name="{$pElName}">
         <xsl:copy-of select="ext:node-set($pQ0)/node()"/>
       </xsl:element>
      </xsl:if>

        <xsl:if test="$pList">
       <xsl:element name="{$pElName}">
         <xsl:apply-templates select="$pFun">
           <xsl:with-param name="pArg1" select="$pQ0"/>
           <xsl:with-param name="pArg2" select="$pList[1]"/>
         </xsl:apply-templates>
       </xsl:element>
        </xsl:if>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

$pQ0 contains the initial value (often zero) for the operation and is the
result when an empty list is provided. The results are "accumulated" in
$pQ0 -- that is when the scanl template calls itself recursively, it passes
the last of all results. All intermediate results are output.

$pFun must be a template reference to a template (a node, matched by this
template) that performs the step operation.
This template must have two xsl:param children named "pArg1" and "pArg2".
pArg1 contains the (last) current accumulated result. pArg2 is the top
element of the current list.

$pList is the list of elements that must be processed.

The other parameters have default values and one should not worry (and
generally is not expected to know) about them.

This template is a little bit longer, because it implements DVC-style
recursive processing, splitting the list in two halves, processing
recursively the first half and then using the result of this first half's
processing as pQ0 for the recursive processing of the second half of the
list. This ensures that there will not be a stack overflow due to
excessively deep recursive processing.


The same in XSLT2 is implementid like this:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
 xmlns:xs="http://www.w3.org/2001/XMLSchema";
 xmlns:f="http://fxsl.sf.net/";
 xmlns:int="http://fxsl.sf.net/dvc-scanl/int";
 exclude-result-prefixes="f int xs"

  <xsl:import href="func-apply.xsl"/>

  <xsl:function name="f:scanl">
    <xsl:param name="pFun" as="element()"/>
    <xsl:param name="pQ0"/>
    <xsl:param name="pList" as="item()*"/>

    <xsl:sequence select="int:scanl($pFun, $pQ0, $pList, 1)"/>
  </xsl:function>

  <xsl:function name="int:scanl">
    <xsl:param name="pFun" as="element()"/>
    <xsl:param name="pQ0"/>
    <xsl:param name="pList" as="item()*"/>
    <xsl:param name="pStarting" as="xs:integer"/>

    <xsl:variable name="vLength" select="count($pList)"/>

    <xsl:choose>
      <xsl:when test="$vLength > 1">
        <xsl:variable name="vHalf" select="floor($vLength div 2)"/>

        <xsl:variable name="vResult1"
           select="int:scanl($pFun,
                             $pQ0,
                             $pList[position() &lt;= $vHalf],
                             $pStarting
                             )"/>
       <xsl:sequence select=
         "($vResult1,
           int:scanl($pFun,
                     $vResult1[last()],
                     $pList[position() > $vHalf],
                     0)
          )"
         />
      </xsl:when>

      <xsl:otherwise>
      <xsl:if test="$pStarting">
       <xsl:sequence select="$pQ0"/>
      </xsl:if>

        <xsl:if test="$pList">
          <xsl:sequence select="f:apply($pFun, $pQ0, $pList[1])"/>
        </xsl:if>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:function>
</xsl:stylesheet>

Here the apply() function has the following code:

<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:function name="f:apply">
   <xsl:param name="pFunc" as="element()"/>
   <xsl:param name="arg1"/>

    <xsl:apply-templates select="$pFunc">
      <xsl:with-param name="arg1" select="$arg1"/>
    </xsl:apply-templates>
  </xsl:function>

  <xsl:function name="f:apply">
   <xsl:param name="pFunc" as="element()"/>
   <xsl:param name="arg1"/>
   <xsl:param name="arg2"/>

    <xsl:apply-templates select="$pFunc">
      <xsl:with-param name="arg1" select="$arg1"/>
      <xsl:with-param name="arg2" select="$arg2"/>
    </xsl:apply-templates>
  </xsl:function>


  <xsl:function name="f:apply">
   <xsl:param name="pFunc" as="element()"/>
   <xsl:param name="arg1"/>
   <xsl:param name="arg2"/>
   <xsl:param name="arg3"/>

    <xsl:apply-templates select="$pFunc">
      <xsl:with-param name="arg1" select="$arg1"/>
      <xsl:with-param name="arg2" select="$arg2"/>
      <xsl:with-param name="arg3" select="$arg3"/>
    </xsl:apply-templates>
  </xsl:function>

<!-- Etc. All function definitions untill defined for up to ten
arguments -->

</xsl:stylesheet>


I would be glad to answer any further questions you might have.


=====
Cheers,

Dimitre Novatchev.
http://fxsl.sourceforge.net/ -- the home of FXSL


"Ficke, Bill" <Bill(_dot_)Ficke(_at_)austinenergy(_dot_)com> wrote in message
news:92EFB80E551BD511B39500D0B7B0CDCC0A993F90(_at_)ohms(_dot_)electric(_dot_)ci(_dot_)austin(_dot_)tx(_dot_)us(_dot_)(_dot_)(_dot_)
Dimitre,

Thank you for helping me.  I am sorry for not removed excess code from my
stylesheet.  I thought you were asking for more xml, not less xsl.

I have examined your example code provided in your last email, and it
appears that my code is structured very similarly to it.  It is difficult
for me to see where and how the running total is stored during execution.

I'm assuming that downloading fxsl, I'll be able to see the templates
scan1
and scanl1 referred to below.  Is that true?  I really need a working
example to understand how to apply it to my situation.

Thank you again for patiently working with me.

Bill




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



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