103

With the help of this SO question I have an almost working xpath:

//div[contains(@class, 'measure-tab') and contains(., 'someText')]

However this gets two divs: in one it's the child td that has someText, the other it's child span.

How do I narrow it down to the one with the span?

<div class="measure-tab">
  <!-- table html omitted -->
  <td> someText</td>
</div>

<div class="measure-tab">  <-- I want to select this div (and use contains @class)
  <div>
    <span> someText</span>  <-- that contains a deeply nested span with this text
  </div>
</div>
5
  • 1
    YOu need to post input xml atleast a part of what you want to write xpath for ? Commented Aug 14, 2016 at 13:52
  • Do you mean ...and contains(span, 'someText')]? Commented Aug 14, 2016 at 13:56
  • That's what I thought, but then I get "no matching nodes" in FirePath validator Commented Aug 14, 2016 at 13:59
  • @SamiKuhmonen - Close. It would be ` and contains(div/span, 'someText')]` Commented Aug 14, 2016 at 14:08
  • 1
    Yes, seeing the example it would be div/span Commented Aug 14, 2016 at 14:09

5 Answers 5

159

To find a div of a certain class that contains a span at any depth containing certain text, try:

//div[contains(@class, 'measure-tab') and contains(.//span, 'someText')]

That said, this solution looks extremely fragile. If the table happens to contain a span with the text you're looking for, the div containing the table will be matched, too. I'd suggest to find a more robust way of filtering the elements. For example by using IDs or top-level document structure.

Sign up to request clarification or add additional context in comments.

4 Comments

Screen-scraping is always by its nature pretty fragile.
is there any way to select an element whose child's class contains specific text?
@oldboy: //button[contains(text(), "11") and contains(@class, "MuiPickersDay-day") and .//span[contains(@class, "Mui")]]
@Andy thx hopefully it will help somebody out in the future
27

You can use ancestor. I find that this is easier to read because the element you are actually selecting is at the end of the path.

//span[contains(text(),'someText')]/ancestor::div[contains(@class, 'measure-tab')]

1 Comment

More info on "axes" (of which ancestor is one): w3schools.com/xml/xpath_axes.asp
21

You could use the xpath :

//div[@class="measure-tab" and .//span[contains(., "someText")]]

Input :

<root>
<div class="measure-tab">
  <td> someText</td>
</div>
<div class="measure-tab">
  <div>
    <div2>
       <span>someText2</span>
   </div2>
  </div>
</div>
</root>

Output :

    Element='<div class="measure-tab">
  <div>
    <div2>
      <span>someText2</span>
    </div2>
  </div>
</div>'

3 Comments

That would select the span and not the div.
I thought OP wanted span
I tried to make it as explicit as possible with the <-- comment :)
3

You can change your second condition to check only the span element:

...and contains(div/span, 'someText')]

If the span isn't always inside another div you can also use

...and contains(.//span, 'someText')]

This searches for the span anywhere inside the div.

1 Comment

Accepting nwellnhof's answer as he got it first, but +1 for the alternative. cheers.
1

You can simply do it this way:

//div[contains(text(),'someText')][@class='measure-tab']

This XPath expression will select all div elements in the DOM that contain the text 'someText' and have a class attribute with the value 'measure-tab'.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.