20

I would like to locate this element,

<div class="item-price">$0.99</div>

using XPath which says select div elements whose class attribute equals "item-price" and whose content contains a dollar sign ($).

kjhughes
  • 106,133
  • 27
  • 181
  • 240
Terrence Brannon
  • 4,760
  • 7
  • 42
  • 61
  • 1
    An attribute is matched with `@attributename`, you can use the `contains()` function on the content. Could you give us your best effort using those 2? – Wrikken Oct 21 '13 at 20:15
  • OK. `//div[@class="item-price" and contains("$")]` but I'm unsure of how to make conjunctions. I've also seen `//div[one][theother]`. – Terrence Brannon Oct 21 '13 at 20:28
  • 1
    Have you looked at the [documentation of `contains()`](http://www.w3.org/TR/xpath/#function-contains)? You're very close (`contains(.,'$')` would do it) – Wrikken Oct 21 '13 at 20:35

3 Answers3

33

This XPath expression:

//div[contains(@class, 'item-price') and contains(., '$')]

Will match all div elements of the item-price class containing a '$'.

It's useful to use contains() in the test on @class if you want to match cases where there are multiple CSS styles specified in the @class value.


Caution: For a more robust solution, apply the following technique to avoid unintended substring matches (item-price matching, say, item-prices):

//div[contains(concat(' ',@class,' '), ' item-price ') and contains(., '$')]
kjhughes
  • 106,133
  • 27
  • 181
  • 240
  • 1
    I like the telepathic support you are giving me by telling me about `contains()` because it is very valuable. I like the conjunctive syntax used above a bit more. So I'm torn on which to select as the answer because both are correct. – Terrence Brannon Oct 22 '13 at 14:08
  • 4
    You're welcome for the telepathic support. After nearly 5 years, perhaps you're now able to select one answer or the other to [**accept**](https://meta.stackexchange.com/q/5234/234215) now? :-) – kjhughes Aug 03 '18 at 11:42
  • For me for the solution with spaces to work I needed to add the `normalize-space`, for example: `//div[contains(concat(' ',normalize-space(@class),' '),' foobar ')]` [source](https://devhints.io/xpath) – Aidas Feb 01 '23 at 20:12
  • @Aidas: What was your `@class` value such that it required `normalize-space()`? – kjhughes Feb 01 '23 at 20:58
  • My `class` attribute had 3 values, in short: `class=a b c`. I wanted to search by `a`. So for me it wasn't working when I tried to apply spaces at various places, for example `a`, `a ` etc. Only when I applied `normalize-space()` on `@class` the magic happened. On second glance, this may not be related to this particular issue, still I thought leaving a comment might help somebody. :) – Aidas Feb 01 '23 at 22:51
  • @Aidas: I agree with your second glance: It would not have been [`normalize-space()`](https://stackoverflow.com/q/55854177/290085) that resolved your issue. – kjhughes Feb 02 '23 at 02:34
8
//div[@class = 'item-price'][contains(., '$')]
Michael Kay
  • 156,231
  • 11
  • 92
  • 164
2

As per the HTML:

<div class="item-price">$0.99</div>

There is:

  • Only one value of the class attribute i.e. item-price
  • And the innerText starts with a $ sign.

So, to locate this element with respect to the value of the class attribute i.e. item-price and innerText content starting with a dollar sign ($) you can use either of the following solutions:

  • Using starts-with():

    //div[@class='item-price' and starts-with(., '$')]
    
  • Using contains():

    //div[@class='item-price' and contains(., '$')]
    
undetected Selenium
  • 183,867
  • 41
  • 278
  • 352