[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

Re: params - keys? how to calculate product of parents

Subject: Re: params - keys? how to calculate product of parents with multiple children
From: Dimitre Novatchev <dnovatchev@xxxxxxxxx>
Date: Thu, 14 Apr 2005 06:33:21 +1000
calculate xml
On 4/14/05, Michael Kay <mike@xxxxxxxxxxxx> wrote:
>
> The first part, dividing the two (so-called) attributes is easy:
>
> RECORDITEM[@sqlsource='oldshares'] div RECORDITEM[@sqlsource='newshares']
>
> The next bit is more difficult. There's no built-in function (like sum())
> that takes the product of a set of numbers, but Dimitre's FXSL library
makes
> it very easy to define one of your own. If he's listening, I'm sure he'll
> tell you how.

In XSLT 2.0 using FXSL one will simply use f:product and the whole
transformation is the result of just a single XPath expression:

<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="../f/func-product.xsl"/>

    <xsl:output  encoding="UTF-8" omit-xml-declaration="yes"/>

   <!-- This transformation should be applied to:
        testProduct.xml
     -->

    <xsl:template match="/">
      <xsl:value-of select=
      "f:product(/*/*/*/*/(*[@sqlsource='newshares']
                                  div
                                   *[@sqlsource='oldshares']))"/>
    </xsl:template>
</xsl:stylesheet>


When applied on the OP's source xml it produces the wanted result:

  0.25

Here's the code for the f:product() function:

func-product.xsl:
============
<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/"
exclude-result-prefixes="f xs"
>
   <xsl:import href="func-foldl.xsl"/>
   <xsl:import href="../f/func-Operators.xsl"/>

    <xsl:function name="f:product">
      <xsl:param name="pList"/>
      <xsl:sequence select="f:foldl(f:mult(), 1, $pList)"/>
    </xsl:function>

</xsl:stylesheet>


If someone loves writing expressions from scratch, they could
substitute f:product() in the first transformation with the expression
from the last transformation and they would still get a single XPath
expression for the solution of the problem:


f:foldl(f:mult(), 1, /*/*/*/*/(*[@sqlsource='newshares']
                                     div
                                        *[@sqlsource='oldshares']))
          )


Cheers,
Dimitre Novatchev


>
> The alternative is to do a recursive scan of the values: write a template
> (or XSLT 2.0 function) that takes a RECORDSECTION as an argument and the
> product-so-far as a second argument. Compute the value above, multiply it
by
> the product-so-far, and call the template with the following-sibling
> RECORDSECTION and the new product as the arguments. Start the thing off by
> calling this template/function with the first RECORDSECTION and the value 1
> as arguments, terminate the recursion when there are no following siblings.
>
> Michael Kay
> http://www.saxonica.com/
>
>
> > -----Original Message-----
> > From: Whitney, Dan (CanWest Interactive)
> > [mailto:DWhitney@xxxxxxxxxxx]
> > Sent: 13 April 2005 13:58
> > To: 'mulberry - xsl'
> > Subject:  params - keys? how to calculate product of
> > parents with multiple children
> >
> >
> > Hi am having trouble conceptualizing how/if I can calculate
> > the following:
> > I want to take the children of RECORDSECTION and divide
> > attribute value
> > newshares by attribute value oldshares.
> > I then want to multiply the results of each those
> > calculations (there may be
> > 0 - any number of occurrences of RECORDSECTION). So for below
> > it would be:
> > (1/2)*(1/2)= 0.25
> >
> > Any help/examples would be appreciated.
> >
> > Dan Whitney
> >
> > XML
> >
> > <?xml version="1.0" encoding="windows-1252"?>
> > <?xml-stylesheet type="text/xsl" href="test/split_total.xsl"?>
> >
> > <PUBLICATION>
> > <DOCUMENT source="splits" group="surveys" output="body">
> > <RECORD fragment="splits" recid="12129" fragid="13" product="surveys"
> > group="surveys" status="1"><ID idtype="fpid">12129</ID>
> > <RECORDSECTION docfragment="splits">
> > <RECORDITEM sqlsource="oldshares">2</RECORDITEM>
> > <RECORDITEM sqlsource="newshares">1</RECORDITEM>
> > </RECORDSECTION>
> > <RECORDSECTION docfragment="splits">
> > <RECORDITEM sqlsource="oldshares">2</RECORDITEM>
> > <RECORDITEM sqlsource="newshares">1</RECORDITEM>
> > </RECORDSECTION>
> > </RECORD>
> > </DOCUMENT>
> > </PUBLICATION>
> >
> > XSL
> >
> > <xsl:stylesheet
> >     version="1.0"
> >     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
> >
> > <xsl:output
> >     method="html"
> >     encoding="iso-8859-1"
> >     indent="yes"
> >     version="4.0"/>
> >
> >
> > <xsl:template match="PUBLICATION">
> >   <table border="0" cellpadding="2" cellspacing="2"
> > width="410" cols="2" >
> >     <tr>
> >       <td>
> >       <xsl:for-each select="DOCUMENT/RECORD">
> > <!-- below would like to only define param once but have it
> > increment based
> > on position-->
> >         <xsl:variable name="product[position()]"
> > select="RECORDSECTION[1]/RECORDITEM[@sqlsource='newshares'] div
> > RECORDSECTION[1]/RECORDITEM[@sqlsource='oldshares']"/>
> >         <xsl:variable name="product[position()]"
> > select="RECORDSECTION[2]/RECORDITEM[@sqlsource='newshares'] div
> > RECORDSECTION[1]/RECORDITEM[@sqlsource='oldshares']"/>
> > <!-- this was a half conceived attempt
> >         <xsl:for-each select="RECORDSECTION[1]">
> >           <xsl:call-template name="splitfactor">
> >             <xsl:with-param name="factor-subset"
> > select="following-sibling::RECORDSECTION"/>
> >           </xsl:call-template>)
> >         </xsl:for-each>
> > -->
> > <!-- here don't even know how I would write this -->
> >         <xsl:value-of select="$product1 * $product2"/>
> >       </xsl:for-each>
> >       </td>
> >     </tr>
> >   </table>
> > </xsl:template>
> >
> > <!-- half conceived attempt -->
> > <xsl:template name="splitfactor">
> >   <xsl:param name="factor-subset" select="1"/>
> >   <xsl:if test="$factor-subset[1]">
> >     <xsl:call-template name="splitfactor">
> >       <xsl:with-param name="factor-subset"
> > select="$factor-subset[position()
> > &gt; 1]"/>
> >     </xsl:call-template>
> >   </xsl:if>
> > </xsl:template>
> >
> > <xsl:template match="ID"/>
> >
> > </xsl:stylesheet>

Current Thread

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2013 All Rights Reserved.