Sum over computed value ?

T

Thomas Zangl

Hi!

I have an XML like this:

<?xml version="1.0" encoding="UTF-8"?>
<invoice>
<bill>
<BId>20</BId>
<CId>73</CId>
<BDate>2006-01-10</BDate>
<BStatus>0</BStatus>
</bill>

<billitems>

<item>
<PName>Kiwi</PName>
<PPrice>0.900</PPrice>
<PId>1</PId>
<BCQuant>15</BCQuant>

</item>

<item>
<PName>Apfel</PName>
<PPrice>0.500</PPrice>
<PId>3</PId>
<BCQuant>10</BCQuant>

</item>

</billitems>
</invoice>

Now I want to have the sum of
/invoice/billitems/item/BCQuant*/invoice/billitems/item/PPrice

(=total price)
Any ideas how to do?

TIA!
 
M

Martin Honnen

Thomas Zangl wrote:

<invoice>
<billitems>

<item>
<PName>Kiwi</PName>
<PPrice>0.900</PPrice>
<PId>1</PId>
<BCQuant>15</BCQuant>

</item>

<item>
<PName>Apfel</PName>
<PPrice>0.500</PPrice>
<PId>3</PId>
<BCQuant>10</BCQuant>

</item>

</billitems>
</invoice>

Now I want to have the sum of
/invoice/billitems/item/BCQuant*/invoice/billitems/item/PPrice

XPath 2.0 with a for..in expression has the expressive power to do that
easily and with one expression e.g.

<xsl:value-of select="sum(for $item in invoice/billitems/item return
$item/PPrice * $item/BCQuant)" />

If you want to do it with XSLT 1.0 and XPath 1.0 then you need to write
a recursive template where you pass in the item elements, compute the
BCQuant * PPPrice for the first item and pass that value and the
remaining items to the template until all items have been processed:

<xsl:template name="computeTotal">
<xsl:param name="items" />
<xsl:param name="currentTotal" select="0" />
<xsl:choose>
<xsl:when test="$items">
<xsl:call-template name="computeTotal">
<xsl:with-param name="items"
select="$items[position() &gt; 1]" />
<xsl:with-param name="currentTotal"
select="$items[1]/PPrice * $items[1]/BCQuant + $currentTotal" />
</xsl:call-template>
</xsl:when>
<xsl:eek:therwise>
<xsl:value-of select="$currentTotal" />
</xsl:eek:therwise>
</xsl:choose>
</xsl:template>

<xsl:template match="/">
<html>
<head>
<title>sum</title>
</head>
<body>
<p>Sum is:
<xsl:call-template name="computeTotal">
<xsl:with-param name="items"
select="invoice/billitems/item" />
</xsl:call-template>
</p>
</body>
</html>
</xsl:template>
 
A

Andrew Schorr

Just for fun, here's how to do it using xgawk (from
http://sourceforge.net/projects/xmlgawk):

xgawk -lxml '
{
switch (XMLEVENT) {
case "STARTELEM":
PATH = PATH"/"XMLNAME
if (PATH == "/invoice/billitems/item")
delete chardata
break
case "CHARDATA":
if ($1 != "")
chardata[PATH] = $0
break
case "ENDELEM":
if (PATH == "/invoice/billitems/item")
sum += chardata["/invoice/billitems/item/BCQuant"]* \
chardata["/invoice/billitems/item/PPrice"]
PATH = substr(PATH,1,length(PATH)-length(XMLNAME)-1)
break
}
}

END {
printf "Sum = %.3f\n",sum
}'
 
W

William Park

Thomas Zangl said:
Hi!

I have an XML like this:

<?xml version="1.0" encoding="UTF-8"?>
<invoice>
<bill>
<BId>20</BId>
<CId>73</CId>
<BDate>2006-01-10</BDate>
<BStatus>0</BStatus>
</bill>

<billitems>

<item>
<PName>Kiwi</PName>
<PPrice>0.900</PPrice>
<PId>1</PId>
<BCQuant>15</BCQuant>

</item>

<item>
<PName>Apfel</PName>
<PPrice>0.500</PPrice>
<PId>3</PId>
<BCQuant>10</BCQuant>

</item>

</billitems>
</invoice>

Now I want to have the sum of
/invoice/billitems/item/BCQuant*/invoice/billitems/item/PPrice

(=total price)
Any ideas how to do?


You need XML parser and floating point calculator. Fortunately, Bash
shell can do both. (See my .sig)

start() # Usage: start tag att=value ...
{
case ${XML_TAG_STACK[0]} in
item) BCQuant=0 PPrice=0 ;;
billitems) rpn clear ;;
esac
}
data() # Usage: data text
{
case ${XML_TAG_STACK[*]|,.} in
BCQuant.item.billitems.invoice) BCQuant="$1" ;;
PPrice.item.billitems.invoice) PPrice="$1" ;;
esac
}
end() # Usage: end tag
{
case ${XML_TAG_STACK[0]} in
item) rpn $BCQuant $PPrice x + =x ;;
esac
}
expat -s start -d data -e end file.xml

The above code will give you running sum. 'rpn' is shell builtin
command, which is full RPN calculator (modelled after HP-42S).

--
William Park <[email protected]>, Toronto, Canada
ThinFlash: Linux thin-client on USB key (flash) drive
http://home.eol.ca/~parkw/thinflash.html
BashDiff: Super Bash shell
http://freshmeat.net/projects/bashdiff/
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,001
Messages
2,570,254
Members
46,851
Latest member
CliftonCor

Latest Threads

Top