Finding div containing text - html

I have the following HTML and and XPath working
<div class="panel panel-default">
<div class="panel-heading"><h1>Text to find</h1></div>
<div class="panel-body">
<div>
...
</div>
</div>
</div>
XPath:
.//div[div[#class[contains(.,'panel-heading')]][.//*[text()='Text to find']]]
The XPath expression will select the outer <div>.
Now if I remove the <h1> tag the XPath expression will no longer find the outer div. Can anyone explain me why, and what to do instead if I want to get the same result in the two cases.

That's because .//* part returns descendant elements of the <div class="panel-heading">. When you remove the h1 tag, the text node 'Text to find' is no longer contained in any descendant element (it is direct child of the context element now), hence can't be found using expression .//*[text()='Text to find'].
To make it work with and without h1 element, you can alter the predicate expression mentioned above to .//text()[.='Text to find'] :
.//div[div[#class[contains(.,'panel-heading')]][.//text()[.='Text to find']]]
.//text() simply returns descendant text nodes from current context element.

Related

XPath for text based on content in preceding element?

<div class="profile-row">
<div class="profile-cell">
<h4 class="">Telephone</h4>
</div>
<div class="profile-cell">
<p class="">0207 289 2981</p>
</div>
</div>
I am trying to grab the phone number: 0207 289 2981
Using variations of:
//h4[starts-with(., 'Telephone')]/following-sibling::div[#class='profile-cell']
and:
//h4[starts-with(., 'Telephone')]/following-sibling::div/p
Can't seem to grab this.
Siblings have a common parent; h4 and p do not.
Use following:: instead.
This XPath,
//h4[.='Telephone']/following::p[1]/text()
will select the text of the immediately following p from your targeted h4.
Here is the xpath.
(//div[#class='profile-cell']//p)[last()]
The problem in your xpath is there is no sibling div to the h4. so you have to access the parent div and then select the sibling div as shown below.
//h4[starts-with(., 'Telephone')]/parent::div/following-sibling::div[#class='profile-cell']/p
This selects the actual number:
//p[#class='']/text()

XPath get element with text in child element

I would like to match a <button> element with a certain text, which is sometimes closed in another element within the button, eg.:
<div #class="buttonset">
<button>Close</button>
</div>
<div #class="buttonset">
<button>
<span>Close</span>
</button>
</div>
The xpath query //div[#class='modal-buttonset']/button[text()='Cancel'] gives me only result from the highest level.
How to match the text on all levels?
Try the following:
//div/button[descendant::text()="Close"]
This XPath,
//button[normalize-space() = 'Close']
will select all button elements whose space-normalized string value is 'Close', regardless of any additional wrapper elements, as requested.

XPath for getting nodes from HTML fragment based on element text content

I need an XPath expressions for the following HTML fragment (DOM structure)
<div class="content">
<div class="product-compare-row">
<div class="spec-title half-size">Model</div>
<div class="spec-values half-size">
<span class="spec-value">kast</span>
</div>
</div>
So I need the kast value if the spec-title div contains Model.
I've tried //div[preceding-sibling::div[contains(.,"Model)")]] but that doesn't work.
The XPath you are looking for is:
//div[contains(#class, "spec-title") and contains(text(), "Model")]/following-sibling::div/span/text()
It is a little bit tricky to follow, but in plain English:
Select all div elements who have a class spec-title and who have text that contains 'Model'.
Find any of this div's following siblings if they are a div.
Traverse to any of their children which are a span and return their text.

Cannot find correct element with same class name

I have the following HTML snippet:
<div id="result-1">
<div class="page">
<div class="collapsingblock">
<h4>Click Me</h4>
</div>
<div class="collapsingblock collapsed">
<h4>No, Click Me</h4>
</div>
</div>
</div>
What I'm trying to do, is to find the second collapsingblock and it's h4
I have the following:
(//div[#id="result-1"]/div[#class="page"]/div[#class="collapsingblock"])[2]/h4
My xPath doesn't return the element. If I replace it with [1] it finds the first instance of collapsingblock though
Any ideas?
Thanks
UPDATE:
I have just noticed, that the HTML is using JavaScript to add/remove an additional class to the second collapsingblock, which collapsed
The problem is that the value of the class attribute of the second inner div element is not equal to "collapsingblock", as you can see:
<div class="collapsingblock collapsed">
<h4>No, Click Me</h4>
</div>
Even though class has very clear-cut semantics in HTML, it does not mean anything special to XPath, it's an attribute like any other.
Use contains() to avoid this problem:
(//div[#id="result-1"]/div[#class="page"]/div[contains(#class,"collapsingblock")])[2]/h4
Then, the only result of the expression above is
<h4>No, Click Me</h4>
By the way, parentheses around the lefthand part of the expression are not necessary in this case:
//div[#id="result-1"]/div[#class="page"]/div[contains(#class,"collapsingblock")][2]/h4
will do exactly the same, given this particular input document.
the parenthesis is necessary because of priority :
(//div[#id="result-1"]/div[#class="page"]/div[#class="collapsingblock"])[2]/h4

XPath selecting explicit element comparing on value

This is what I have tried so far..
//div[#id='information']//div[div=='Site']
//div[text()='Site']//span//a[#href]
I am fiddling with an XPath expression but it´s not working out. I want to select the anchor's href attribute. Thats no problem but it needs to be explicitly after a div with class h3 AND a value = "Site".
<div id="information">
<div class="h3">Location</div>
<div class="h3">Site</div>
<span>
//Here is sometimes a <br/>
<a href='http://www.test.at'>Klick</a>
</span>
<div class="h3">Referenz</div>
<span>12345</span>
</div>
There can be arbitrarily many div elements inside the div with id="information" so selecting on index is not possible.
Something like this should work:
//div[#class = 'h3'][. = 'Site']/following-sibling::*/descendant-or-self::a/#href
This will extract the href attributes of all a tags that are after the "Site" div in document order but still contained within the same parent element (the "information" div in your example). If you're not bothered about that last bit, i.e. you want to include a tags that occur after the "information" div as well as inside it, then you can use the simpler
//div[#class = 'h3'][. = 'Site']/following::a/#href