Reputation: 11
Currently getting a NaN error within XSLT. I want to get the total value or revenue for all products and their quantities ordered.
XML:
<customers>
<customer>
<customername>John</customername>
</customer>
<invoices>
<invoice>
<invoicenumber>01</invoicenumber>
<products>
<product>
<productname>candy bar</productname>
<productamount>6</productamount
<productcost>2</productcost>
</product>
</products>
</invoice>
<invoice>
<invoicenumber>02</invoicenumber>
<products>
<product>
<productname>choco bar</productname>
<productamount>3</productamount
<productcost>1</productcost>
</product>
</products>
</invoice>
</invoices>
<customer>
<customername>Fritz</customername>
</customer>
<invoices>
<invoice>
<invoicenumber>01</invoicenumber>
<products>
<product>
<productname>Soda</productname>
<productamount>3</productamount
<productcost>2</productcost>
</product>
</products>
</invoice>
<invoice>
<invoicenumber>02</invoicenumber>
<products>
<product>
<productname>lollipop</productname>
<productamount>5</productamount
<productcost>1</productcost>
</product>
</products>
</invoice>
</invoices>
And I have tried to adapt a Recursive template.
XSL:
Total:
<xsl:call-template name="sumProducts">
<xsl:with-param name="pNodes" select="customers/customer/invoices/invoice/products"/>
<xsl:with-param name="pName1" select="././././././productamount"/>
<xsl:with-param name="pName2" select="././././././productcost"/>
</xsl:call-template>
<xsl:template name="sumProducts">
<xsl:param name="pNodes"/>
<xsl:param name="pName1"/>
<xsl:param name="pName2"/>
<xsl:param name="pAccum" select="0"/>
<xsl:choose>
<xsl:when test="not($pNodes)">
<xsl:value-of select="$pAccum"/>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="sumProducts">
<xsl:with-param name="pNodes" select="$pNodes[position() > 1]"/>
<xsl:with-param name="pName1" select="$pName1"/>
<xsl:with-param name="pName2" select="$pName2"/>
<xsl:with-param name="pAccum" select="$pAccum + $pNodes[1]/*[name()=$pName1]
* pNodes[1]/*[name()=$pName2]"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Desired outcome would be Total = 26
Upvotes: 0
Views: 149
Reputation: 70638
I can see a few problems with your XSLT. Firstly the setting of the pNodes parameter is incorrect
<xsl:with-param name="pNodes" select="customers/customer/invoices/invoice/products"/>
From looking at your XML, it needs to be as follows
<xsl:with-param name="pNodes" select="customers/invoices/invoice/products/product"/>
i.e. The invoices element is not within the customer element in your sample, and additionally you want to be summing the individual product elements.
Next, as Ian Roberts has mentioned, pName1 and pName2 look like they should be set to be element names. Currently you are just setting them to the value of whatever of the first occurrence of those elements.
<xsl:with-param name="pName1" select="'productamount'"/>
<xsl:with-param name="pName2" select="'productcost'"/>
Finally, the setting of the pAccum parameter is wrong. You are currently doing this...
<xsl:with-param name="pAccum"
select="$pAccum + $pNodes[1]/*[name()=$pName1] * pNodes[1]/*[name()=$pName2]"/>
But you have missed out a $ before the second pNodes variable. It should be this:
<xsl:with-param name="pAccum"
select="$pAccum + $pNodes[1]/*[name()=$pName1] * $pNodes[1]/*[name()=$pName2]"/>
Here's the full XSLT, which should give you 26
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:call-template name="sumProducts">
<xsl:with-param name="pNodes" select="customers/invoices/invoice/products/product"/>
<xsl:with-param name="pName1" select="'productamount'"/>
<xsl:with-param name="pName2" select="'productcost'"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="sumProducts">
<xsl:param name="pNodes"/>
<xsl:param name="pName1"/>
<xsl:param name="pName2"/>
<xsl:param name="pAccum" select="0"/>
<xsl:choose>
<xsl:when test="not($pNodes)">
<xsl:value-of select="$pAccum"/>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="sumProducts">
<xsl:with-param name="pNodes" select="$pNodes[position() > 1]"/>
<xsl:with-param name="pName1" select="$pName1"/>
<xsl:with-param name="pName2" select="$pName2"/>
<xsl:with-param name="pAccum" select="$pAccum + $pNodes[1]/*[name()=$pName1] * $pNodes[1]/*[name()=$pName2]"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Upvotes: 2
Reputation: 122394
Your recursive template looks OK, I think the problem is with your initial pName1
and pName2
parameter values. Try
<xsl:with-param name="pName1" select="'productamount'"/>
<xsl:with-param name="pName2" select="'productcost'"/>
Your template expects those parameters to be strings containing the names of the relevant elements, which is why you need the single quotes inside the double quoted select
attributes.
Upvotes: 0