开发者

xslt 1 and sum function

I create an invoice management system using xml and PHP but the latest PHP version does not support XSLT 2.0 - therefore I have to look for an sum() alternative. How can I transform the valid xslt 2 function "sum(unitprice * quantity)" to xslt 1.0 ?

The 开发者_StackOverflow中文版XML stuff is based on John's Examples

I tried it with a node-set, but it is not supported "xmlXPathCompOpEval: function node-set not found in"


Actually, sum(price*quantity) isn't valid XSLT 2.0 syntax. I guess you mean something like `sum(for $x in * return $x/price*$x/quantity).

Summing over a computed value in XSLT 1.0 can be done in the following ways:

  • two pass solution, create a node-set in which the nodes hold the computed values, then sum over the node-set

  • recursive solution: write a recursive template that passes the total so far as a parameter, adds sum*quantity for the current node, then recurses to process the remaining nodes

  • higher-order solution: use Dimitre Novatchev's FXSL library

  • extension solution: use extension functions like saxon:sum()


You can simply create a template sumNumbers that adds the two quantities. Addition can be performed in a select statement:

<xsl:template name="sumNumbers">
    <xsl:param name="num1"/>
    <xsl:param name="num2"/>

    <xsl:value-of select="$num1 + $num2" />
</xsl:template>

should work


In XSLT 1.0 you can use the FXSL's map() function/template (and either FXSL's sum() function or the standard XPath sum()) function, as shown in the following example:

Having this XML document:

<sales>
  <sale>
    <price>3.5</price>
    <quantity>2</quantity>
    <Discount>0.75</Discount>
    <Discount>0.80</Discount>
    <Discount>0.90</Discount>
  </sale>
  <sale>
    <price>3.5</price>
    <quantity>2</quantity>
    <Discount>0.75</Discount>
    <Discount>0.80</Discount>
    <Discount>0.90</Discount>
  </sale>
</sales>

we want to get the sum from all the sales -- this is the sum of the products: price* quantity * discount1 * discount2 ...* discountN for each sale.

This XSLT 1.0 transformation:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:f="http://fxsl.sf.net/"
xmlns:ext="http://exslt.org/common"
xmlns:test-map-product="test-map-product"
exclude-result-prefixes="xsl f ext test-map-product"
>
   <xsl:import href="sum.xsl"/>
   <xsl:import href="map.xsl"/>
   <xsl:import href="product.xsl"/>

   <!-- This transformation is to be applied on:
        salesMap.xml

        It contains the code of the "sum of products" from the 
        article "The Functional Programming Language XSLT"
     -->

   <test-map-product:test-map-product/>

   <xsl:output method="text"/>

   <xsl:template match="/">
     <!-- Get: map product /sales/sale -->
     <xsl:variable name="vSalesTotals">
         <xsl:variable name="vTestMap" select="document('')/*/test-map-product:*[1]"/>
         <xsl:call-template name="map">
           <xsl:with-param name="pFun" select="$vTestMap"/>
           <xsl:with-param name="pList1" select="/sales/sale"/>
         </xsl:call-template>
     </xsl:variable>

     <!-- Get sum map product /sales/sale -->
      <xsl:call-template name="sum">
        <xsl:with-param name="pList" select="ext:node-set($vSalesTotals)/*"/>
      </xsl:call-template>
   </xsl:template>

    <xsl:template name="makeproduct" mode="f:FXSL"
      match="test-map-product:*">
      <xsl:param name="arg1"/>

      <xsl:call-template name="product">
        <xsl:with-param name="pList" select="$arg1/*"/>
      </xsl:call-template>
    </xsl:template>
</xsl:stylesheet>

when applied on the above XML document, produces the wanted, correct result:

7.5600000000000005

II. XPath 2.0 solution:

A simplified problem (the originally posted one) can be solved using a simple XPath 2.0 one-liner. If we have this XML document:

<sales>
  <sale>
    <price>3.5</price>
    <quantity>2</quantity>
  </sale>
  <sale>
    <price>3.5</price>
    <quantity>2</quantity>
  </sale>
</sales>

then this XPath 2.0 expression:

sum(/*/sale/(price*quantity))

when evaluated, produces the wanted sum:

14

Here is an XSLT 2.0 - based verification of this fact:

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/*">
     <xsl:sequence select="sum(sale/(price*quantity))"/>
 </xsl:template>
</xsl:stylesheet>

When this transformation is performed on the XML document above, the wanted, correct result is produced:

14
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜