Reputation: 55
I have a XML with several accounts and I'm trying to make the sum of several scores with the format score/max_score.
XML:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="accounts.xsl"?>
<accounts>
<account active="yes">
<id>1</id>
<name>James</name>
<score>50/100</score>
</account>
<account active="yes">
<id>2</id>
<name>Caty</name>
<score>10/100</score>
</account>
<account active="yes">
<id>3</id>
<name>Acacia</name>
<score>30/100</score>
</account>
<account active="yes">
<id>4</id>
<name>James</name>
<score>50/100</score>
</account>
<account active="yes">
<id>5</id>
<name>Scoot_5</name>
<score>40/100</score>
</account>
</accounts>
And XSLT:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:template match="/">
<html>
<body>
<p>
<xsl:value-of select="sum(//accounts/account/score/number(substring-before(.,'/')))"/>
</p>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
However when I run the xml says it has error and does not return the sum. Why?
Upvotes: 1
Views: 1096
Reputation: 163322
It seems that @kjhughes somehow worked out that you were using an XSLT 1.0 processor and that you were running in a web browser.
You need an XSLT 2.0 processor to run this. If you are indeed running in a web browser, consider Saxon-CE, which is currently the only 2.0 processor to run client-side.
Upvotes: 1
Reputation: 111541
The problem is that your XSLT 2.0 transformation won't work in web browsers, which only natively support XSLT 1.0.
For ways of summing over elements in XSLT 1.0, see Michael Kay's answer to XSLT 1 and sum function for general ideas. See Dimitre Novatchev's answer to Multiply 2 numbers and then sum with XSLT for some code samples. For actual support of XSLT 2.0 in web browsers, see Saxon-CE.
I like the recursive approach. Here's how it applies to your problem:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<html>
<body>
<p>
<xsl:call-template name="sumScores">
<xsl:with-param name="pList" select="/accounts/account/score"/>
</xsl:call-template>
</p>
</body>
</html>
</xsl:template>
<xsl:template name="sumScores">
<xsl:param name="pList"/>
<xsl:param name="pAccum" select="0"/>
<xsl:choose>
<xsl:when test="$pList">
<xsl:variable name="vHead" select="$pList[1]"/>
<xsl:call-template name="sumScores">
<xsl:with-param name="pList" select="$pList[position() > 1]"/>
<xsl:with-param name="pAccum"
select="$pAccum + number(substring-before($vHead,'/'))"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$pAccum"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
(Credit: Derived from similar code written by Dimitre Novatchev.)
When this XSLT 1.0 transform is run with your input XML we get the desired HTML output:
<html>
<body>
<p>180</p>
</body>
</html>
Upvotes: 2