Calculations inside XPath expressions?

C

Christofer Dutz

Hi,

I just ran into an interesting situation, where I was not able to write
an xpath expression doing what I want it to. Mabe someone here can help
me ... I hope ;)

Here a sample xml-file I want to do the query on:
<?xml version="1.0" encoding="UTF-8"?>
<cart>
<product count="2" price="10.00" id="sdkjfhdaf-A"/>
<product count="1" price="10.00" id="sdkjfhdaf-A"/>
<product count="1" price="30.00" id="sdkjfhdaf-B"/>
<product count="4" price="12.50" id="sdkjfhdaf-C"/>
<product count="2" price="16.00" id="sdkjfhdaf-A"/>
<product count="3" price="119.00" id="sdkjfhdaf-C"/>
<product count="2" price="13.99" id="sdkjfhdaf-A"/>
<product count="10" price="12.34" id="sdkjfhdaf-B"/>
<product count="3" price="11.00" id="sdkjfhdaf-B"/>
<product count="1" price="1.00" id="sdkjfhdaf-A"/>
</cart>

I would like to test, if the total price for all products in the cart
which have an Id containing "-C" in their id-attribute is biger than
lets say 100.
I have no problem selecting either the price or count attribute of these
but I am unable to get "price * count".
Any suggestions?

I created a workaround by adding an additional total-attribute and
everything is working fine, it's just my scientiffic curiosity ;)

Chris
 
M

Martin Honnen

Christofer Dutz wrote:

Here a sample xml-file I want to do the query on:
<?xml version="1.0" encoding="UTF-8"?>
<cart>
<product count="2" price="10.00" id="sdkjfhdaf-A"/>
<product count="1" price="10.00" id="sdkjfhdaf-A"/>
<product count="1" price="30.00" id="sdkjfhdaf-B"/>
<product count="4" price="12.50" id="sdkjfhdaf-C"/>
<product count="2" price="16.00" id="sdkjfhdaf-A"/>
<product count="3" price="119.00" id="sdkjfhdaf-C"/>
<product count="2" price="13.99" id="sdkjfhdaf-A"/>
<product count="10" price="12.34" id="sdkjfhdaf-B"/>
<product count="3" price="11.00" id="sdkjfhdaf-B"/>
<product count="1" price="1.00" id="sdkjfhdaf-A"/>
</cart>

I would like to test, if the total price for all products in the cart
which have an Id containing "-C" in their id-attribute is biger than
lets say 100.
I have no problem selecting either the price or count attribute of these
but I am unable to get "price * count".
Any suggestions?

XPath (at least version 1.0) alone can't do that, you need an XSLT 1.0
stylesheet with a template that adds up the values as necessary:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">

<xsl:eek:utput method="xml" indent="yes" />

<xsl:param name="matchSubstring" select="'-C'" />

<xsl:template match="/">
<results>
<xsl:call-template name="getTotal">
<xsl:with-param name="products"
select="cart/product[contains(@id, $matchSubstring)]" />
</xsl:call-template>
</results>
</xsl:template>

<xsl:template name="getTotal">
<xsl:param name="products" />
<xsl:param name="currentTotal" select="0" />
<xsl:variable name="currentProduct" select="$products[1]" />
<xsl:choose>
<xsl:when test="not($currentProduct)">
<total>
<xsl:value-of select="$currentTotal" />
</total>
</xsl:when>
<xsl:eek:therwise>
<xsl:call-template name="getTotal">
<xsl:with-param name="products" select="$products[position()
&gt; 1]" />
<xsl:with-param name="currentTotal" select="$currentTotal +
$currentProduct/@Count * $currentProduct/@price" />
</xsl:call-template>
</xsl:eek:therwise>
</xsl:choose>
</xsl:template>

</xsl:stylesheet>
 
C

Christofer Dutz

Hmmm ... I hoped to get a different answer :( ... well that might be the
reason why I was not able to do it ;)
What about newer XPath Versions?
Adding an XSL transformation to this would be some kind of overkill ...
as I said, was just curiosity.

Thanks anyway,
Chris
 
?

=?ISO-8859-1?Q?J=FCrgen_Kahrs?=

Christofer said:
Hmmm ... I hoped to get a different answer :( ... well that might be the
reason why I was not able to do it ;)
What about newer XPath Versions?

Are you really sure you need XPath ?
Adding an XSL transformation to this would be some kind of overkill ...
as I said, was just curiosity.

There are other solutions. Even simple ones.
If other tools are acceptable to you,
I promise to supply a solution (in XMLgawk).
 
M

Martin Honnen

Christofer Dutz wrote:

What about newer XPath Versions?

With XPath 2.0 you could do it with a single expression, using the sum
function on the result returned from a for..in expression:
sum(for $product in /cart/product[contains(@id, $matchSubstring)]
return $product/@Count * $product/@price)

Saxon 8 implements XPath 2.0 while the spec is being developed:
<http://saxon.sourceforge.net/#F8.4SA>
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top