CSS selector equivalent to this nested or embedded XPath? - xpath

There is a type of XPath like this
//div[span[a[#title='foo']]]
where it matches & returns the div (not the hyperlink) that contains a span, which in turn contains a hyperlink with title "foo".
is there a CSS selector format equivalent to this?
I gave it a short trying to convert to CSS, and if there is an equivalent, I don't know how to map it correctly.

No, there isn't. Selectors don't have the kind of predicate that XPath does, and there isn't a way to ascend an element's hierarchy from the deepest element (in this case your a[#title='foo']), i.e. there is no parent selector.

Related

What is the proper way to use descendant in XPath

I am trying to find all DIV elements have the attribute widget-name and a descendant span tag that have a title attribute.
This is what I am trying.
//div[#widget-name and descendant::span[#title]]"
This seems to almost work but it is missing one element in the Nodes Collection it returns.
Never mind.
This is what I needed:
//div[#widget-name and descendant::span[#class='title']]
OK - take it back.
This is not the complete answer.
I am now trying to tweak this to where it returns all except where title is not equal to some text:
//div[#widget-name and descendant::span[#class='title' and [text()[contains(., '{someTextToKeep}'
Anyone see why this would be invalid XPath?
Final answer is:
//div[#widget-name and descendant::span[#class='title' and text()[not(contains(., 'someTextToKeep'))]]]"
This XPath should return all div's that:
has a widget-name attribute
has a descendant span element (used abbreviated syntax) that:
has a class attribute with the value 'title'
contains the text 'someTextToKeep' (if you want to exclude spans with certain text, wrap the contains() in not().
XPath:
//div[#widget-name and .//span[#class='title'][contains(.,'someTextToKeep')]]

Get element name by containing text

I'm looking through HTML documents for the text: "Required". What I need to find is the element that holds the text. For example:
<p>... Required<p>
I would get to element name = p
However, it might not be in a <p> tag. It could be in any kind of tag, which is where this question differs from some of the other search text Stack Overflow questions.
Right now I'm using:
page.at(':contains("Required")')
but this only get me the full HTML element
The problem you have is the :contains pseudo class matches any element that has the searched for text anywhere in its descendants. You need to find the innermost element that contains such text. Since html is the ancestor of all elements, if the page contains the text anywhere then html will contain, and so that will be the first matching element.
I’m not sure you can achieve this with CSS, but you can use XPath like this:
page.at_xpath('//*[text()[contains(., "Required")]]')
This finds the first element node that has a text() node as a child that contains Required. When you have that node (if it exists) you can then call name on it to give the name of the element.
For CSS you can do:
page.at('[text()*="Required"]')
It's not real CSS though, or even a jQuery extra.
You should use CSS selectors:
page.css('p').text

Would like to use wildcard within an xpath

I have two links on a page that have the text 'London'. I want to choose the second one on the page, but I want to define the xpath in a way that it chooses by the parent div, but I want to use wildcard in case the link is moved.
So, the two xpaths are
//div[#id="first-id"]/div/div[2]/a[text()="London"]
//div[#id="second-id"]/div[2]/div[3]/div/a[text()="London"]
I want to use a wildcard and define the xpath within the parent div:
i.e. //div[#id="second-id"]/*/a[text="London"]
I already understand I can just use the full xpath and not have any wildcards, but I want to know if there's a way to do what I am proposing using xpath. I thought maybe contains() in some way would work but am not familiar enough with it.
To find the a element wherever it may appear within the div element, the descendant path is represented simply by //:
//div[#id="second-id"]//a[text="London"]

Do all xpath queries have an equivalent CSS selector

Given any xpath query, can we say that there exists some CSS selector that will match the same elements?
As pointed out in the comments, the answer is an emphatic no.
The simplest way is proof through contradiction, and that is a simple parent selector - ./../. Since the parent of an arbitrary node in an XML document can be retrieved by XPath, but no parent selector exists in CSS, is trivial to say that not every XPath has an equivilent CSS selector.
QED. Ipso facto. Lorum Ipsum.

xpath: find a node whose content has a provided string

I have some HTML like this:
<div> Make </div>
And I want to match it based on the fact that the content of the node contains the text "Make".
Put another way "Make" is a substring of the div node's content and I want to make such a match on this node using XPath.
The obvious solution would be
//div[contains(., 'Make')]
but this will find all divs that contain the string "Make" anywhere within their content, so not only will it find the example you've given in the question but also any ancestor div of that one, or any divs where that substring is buried deep in a descendant element.
If you only want cases where that string is directly inside the div with no other intervening elements then you'd have to use the slightly more complex
//div[text()[contains(., 'Make')]]
This is subtly different from
//div[contains(text(), 'Make')]
which would look only in the first text node child of the div, so it would find <div>Make<br/>Break</div> but not <div>Break<br/>Make</div>
If you want to allow for intervening elements other than div, then try
//div[contains(., 'Make')][not(.//div[contains(., 'Make'])]
Seems like this is what you are looking for: //div[contains(text(),'Make')]
If this will not work you can try: //div[contains(.,'Make')]. This will find all divs, which contain 'Make' in any attribute.
To find that node anywhere in the document, you would need this:
//div[contains(text(), "Make")]

Resources