172

XSL - Multiplying Element Sums

I have a few elements like this:

<item type="goods"> <quantity unit="pcs">172</quantity> <unit-price currency="PLN">420</unit-price> <VAT>7</VAT> </item> 

I want to print the sum of the value of these items. So what mathematically:

 sum(quantity*unit-price) 

How can I do this using xsl? I tried using variables with every loop inside and the usual valye-of. but I am still getting some weird results (I will not add this code since it is just bad).

+4
source share
2 answers

XSLT:

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <xsl:template match="/root"> <xsl:text>sum:</xsl:text> <xsl:call-template name="sum"> <xsl:with-param name="nodes" select="item"/> </xsl:call-template> </xsl:template> <xsl:template name="sum"> <xsl:param name="nodes" /> <xsl:param name="sum" select="0" /> <xsl:variable name="current" select="$nodes[1]" /> <xsl:if test="$current"> <xsl:call-template name="sum"> <xsl:with-param name="nodes" select="$nodes[position() &gt; 1]" /> <xsl:with-param name="sum" select="$sum + $current/quantity * $current/unit-price" /> </xsl:call-template> </xsl:if> <xsl:if test="not($current)"> <xsl:value-of select="$sum" /> </xsl:if> </xsl:template> </xsl:stylesheet> 

XML input:

 <root> <item type="goods"> <quantity unit="pcs">1</quantity> <unit-price currency="PLN">2</unit-price> <VAT>7</VAT> </item> <item type="goods"> <quantity unit="pcs">10</quantity> <unit-price currency="PLN">20</unit-price> <VAT>7</VAT> </item> <item type="goods"> <quantity unit="pcs">100</quantity> <unit-price currency="PLN">200</unit-price> <VAT>7</VAT> </item> </root> 

Output:

 sum:20202 
+10
source

In addition to Cyril's correct answer:

I. XPath 2.0 Solution (XSLT 2.0) :

Use this single XPath 2.0 expression from any language in which XPath 2.0 is hosted:

 sum(/*/*/(quantity*unit-price)) 

Here is a complete example of using XSLT 2.0 as an XPath 2.0 host:

 <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(/*/*/(quantity*unit-price))"/> </xsl:template> </xsl:stylesheet> 

when applied to the following XML document :

 <items> <item type="goods"> <quantity unit="pcs">1</quantity> <unit-price currency="PLN">2</unit-price> <VAT>7</VAT> </item> <item type="goods"> <quantity unit="pcs">10</quantity> <unit-price currency="PLN">20</unit-price> <VAT>7</VAT> </item> <item type="goods"> <quantity unit="pcs">100</quantity> <unit-price currency="PLN">200</unit-price> <VAT>7</VAT> </item> </items> 

required, the correct result is obtained :

 20202 

II. XSLT 1.0 using transform-and-sum template / function FXSL 1.x

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:f="http://fxsl.sf.net/" xmlns:func-transform="ff:func-transform" exclude-result-prefixes="xsl func-transform" > <xsl:import href="transform-and-sum.xsl"/> <!-- to be applied on testTransform-and-sum5.xml --> <xsl:output method="text"/> <func-transform:func-transform/> <xsl:template match="/"> <xsl:call-template name="transform-and-sum"> <xsl:with-param name="pFuncTransform" select="document('')/*/func-transform:*[1]"/> <xsl:with-param name="pList" select="/*/*"/> </xsl:call-template> </xsl:template> <xsl:template match="func-transform:*" mode="f:FXSL"> <xsl:param name="arg1" select="0"/> <xsl:value-of select="$arg1/quantity * $arg1/unit-price "/> </xsl:template> </xsl:stylesheet> 

when this conversion is applied to the same XML document (above), the same correct result is obtained :

 20202 

Pay attention . Using FXSL, there is no need to implement explicit recursion "for the Nth time", the solution is compact and potential errors that write recursion are completely eliminated.

Overall, overall development time, readability, and flexibility are greatly improved.

+3
source

Source: https://habr.com/ru/post/1386914/


All Articles