How to ignore non visible elements in xPath? - xpath

I want to ignore elements from my xpath query that are not visible, either because they or any of their ancestors are display:none.
I tried the below, but it's including elements which non displayable ancestors
//button[
not(contains(#style,'display:none'))
and
not(ancestor::div[contains(#style,'display:none')])
and
contains(translate(., 'ABCDEFGHIJKLMNÑOPQRSTUVWXYZ', 'abcdefghijklmnñopqrstuvwxyz'), 'acept')
]
"

Try to apply this
//*[not(ancestor-or-self::*[contains(#style,'display: none;')])]

Related

XPath: Search for HTML element within HTML element

With XPath, how would you search for elements that only contain another specific element? For example, what expression would result in getting all <p> tags that contain <strong> elements within them?
<p>This is some text that <strong>contains another HTML element</strong></p>
In XPath you use square brackets to filter. It is called the predicate. See I.e. this tutorial .
To select all p’s with a element strong you use
//p[strong]
If you want to find all p’s with only the element strong and no other elements, you add
//p[strong][count(*)=count(strong)]
The * stands for any element.
If, as in your example , you only interested in p’s with the strong element being the last child node you use
//p[strong[not(following-sibling::node())]]
Predicates are the way to go.
what expression would result in getting all p tags that contain elements within them?
If you only want to select p elements with direct strong children, you can use p[strong], if you're looking for any descendants, use p[descendant::strong]. In both cases the context node has to be at the level of the p elements.

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')]]

Text validation on a webpage where multiple elements have the same label

I have the following code as part of a test:
if page.text.include? "Provide your details"
go_and_enter_details
end
The webpage has multiple elements labelled h2, including the one that's being checked for content.
This error is returned:
Ambiguous match, found 3 elements matching css "h2" (Capybara::Ambiguous)
How can get Ruby/Cucumber/Capybara to identify whether the page contains the text I need to check?
You have various options:
if the element you want to fill is the first one in the page, you can use first element
first('YOUR ELEMENT').click
you can use within, so you can tell capybara where to find your element (for example, in a div)
within('body > div > div') do
#find your element and do your work
end
you can use the CSS selector or the XPath of your element

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

XPath intersection of two sets

I need to extract all links from a html document having text as the inner element and not a reference to an image. Basically I would like to do a doc.select("//a/attribute::href") for all elements in a tree where doc.select("//a/text()") returns anything. Thanks!
Well you can write conditions in XPath in a predicate in square brackets, e.g. //a[text()]/#href selects the href attributes of all link (a) elements that have at least one text node child. Or if you want to make sure there is no img child element in the link you can use e.g. //a[not(img)]/#href.

Resources