How to get the sum() of node values in XSLT
First of all, your input document contains a default namespace:
<container xmlns="http://www.gtech.com/lsp/2009-09-23">
that you need to take into account, i.e. redeclare in your stylesheet and prefix elements when referring to the input document.
Then, there is absolutely no need to construct a variable when you can directly sum the nodes you are interested in - but some of the CashPaymentsToday
elements do not contain a number:
<CashPaymentsToday>NONQUAL</CashPaymentsToday>
You need to exclude those elements from the sum. Finally, what you are currently doing is not possible in XSLT 1.0 - because the sum()
function cannot take a so-called result tree fragment as an argument. Your approach should not "only return html", it should actually fail.
XSLT Stylesheet
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:gt="http://www.gtech.com/lsp/2009-09-23"
exclude-result-prefixes="gt">
<xsl:template match="/">
<html>
<body>
<xsl:value-of select="sum(//gt:CashPaymentsToday[. != 'NONQUAL'])"/>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
HTML Output
<html>
<body>310</body>
</html>
![Admin](/assets/logo_square_200-5d0d61d6853298bd2a4fe063103715b4daf2819fc21225efa21dfb93e61952ea.png)
Admin
Updated on August 09, 2022Comments
-
Admin almost 2 years
I am trying to calculate the sum of numeric nodes. The following code doesn't return anything except the HTML. I know that sum() takes a nodeset. I think I have created the variable correctly. What am I doing wrong.
Thanks.
XML Example:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <container xmlns="http://www.gtech.com/lsp/2009-09-23"> <Root> <Incentives> <Date>2015-03-14</Date> <ID>507200</ID> <ProgramName>Retailer Cash Incentive 16</ProgramName> <Retailer> <ID>507201</ID> <Name>Acme #2102</Name> <Detail> <CashPaymentsToday>50.00</CashPaymentsToday> <Potential>0</Potential> </Detail> </Retailer> <Retailer> <ID>507202</ID> <Name>Acme #2103</Name> <Detail> <CashPaymentsToday>60.00</CashPaymentsToday> <Potential>0</Potential> </Detail> </Retailer> <Retailer> <ID>507203</ID> <Name>Acme #1008</Name> <Detail> <CashPaymentsToday>0.00</CashPaymentsToday> <Potential>0</Potential> </Detail> </Retailer> <Retailer> <ID>507207</ID> <Name>Acme #2228</Name> <Detail> <CashPaymentsToday>200.00</CashPaymentsToday> <Potential>3</Potential> </Detail> </Retailer> <Retailer> <ID>598419</ID> <Name>Acme NO 1071</Name> <Detail> <CashPaymentsToday>NONQUAL</CashPaymentsToday> <Potential>NONQUAL</Potential> </Detail> </Retailer> <Retailer> <ID>598421</ID> <Name>Acme NO 1072</Name> <Detail> <CashPaymentsToday>NONQUAL</CashPaymentsToday> <Potential>NONQUAL</Potential> </Detail> </Retailer> </Incentives> </Root> </container>
XSLT:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <html> <body> <xsl:variable name="cashPayments"> <xsl:for-each select="//Detail"> <xsl:if test="CashPaymentsToday"/> </xsl:for-each> </xsl:variable> <xsl:value-of select="sum($cashPayments)"/> </body> </html> </xsl:template> </xsl:stylesheet>
-
bjimba about 9 yearsIf you could possibly get other non-numerics besides 'NONQUAL", you can be more generic, and just test for numeric values:
<xsl:value-of select="sum(//gt:CashPaymentsToday[number(.) = .])"/>
. A fuller discussion of this test can be seen at stackoverflow.com/questions/3854345/xpath-test-if-is-number -
Mathias Müller about 9 years@bjimba Yes, that would be a good approach - but it's also more opaque. Let's wait for the OP to clarify if they indeed have more values that are not numbers.