Calculations inside XPath expressions?

Discussion in 'XML' started by Christofer Dutz, Apr 10, 2005.

  1. 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
     
    Christofer Dutz, Apr 10, 2005
    #1
    1. Advertising

  2. 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>

    --

    Martin Honnen
    http://JavaScript.FAQTs.com/
     
    Martin Honnen, Apr 10, 2005
    #2
    1. Advertising

  3. 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

    Martin Honnen wrote:

    > 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>
    >
     
    Christofer Dutz, Apr 10, 2005
    #3
  4. Christofer Dutz wrote:

    > 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).
     
    =?ISO-8859-1?Q?J=FCrgen_Kahrs?=, Apr 10, 2005
    #4
  5. 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>


    --

    Martin Honnen
    http://JavaScript.FAQTs.com/
     
    Martin Honnen, Apr 10, 2005
    #5
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Jay Douglas
    Replies:
    0
    Views:
    618
    Jay Douglas
    Aug 15, 2003
  2. Thor W Hammer
    Replies:
    0
    Views:
    1,766
    Thor W Hammer
    Mar 14, 2006
  3. Neil Zanella

    mozilla and XPath Expressions

    Neil Zanella, Dec 9, 2003, in forum: XML
    Replies:
    2
    Views:
    734
    Neil Zanella
    Dec 14, 2003
  4. Tjerk Wolterink

    XPath: efficiency in xpath expressions

    Tjerk Wolterink, Nov 13, 2004, in forum: XML
    Replies:
    1
    Views:
    1,661
    Richard Tobin
    Nov 13, 2004
  5. Noman Shapiro
    Replies:
    0
    Views:
    239
    Noman Shapiro
    Jul 17, 2013
Loading...

Share This Page