Too many results when finding within element with Selenium WebDriver - java

I did the following search
parts.get(i).findElements(By.xpath("//li[starts-with(#class, '_lessons--row-')]"))
and it returned dozens of results, while I see in Developer Tools, that there are no more than 3 of them.
parts.get(i) returns single WebElement.
Looks like it searches not children of a given element, but over entire page. Can double slash cause this? What double slash means in XPath?

Your xpath is faulty here.
"//li[starts-with(#class, '_lessons--row-')]"
// searches from root level, to search from node preappend .:
".//li[starts-with(#class, '_lessons--row-')]"

Try your xpath with .// , normally you should start xpath with "." to stop finding elements from root.
.//li[starts-with(#class, '_lessons--row-')]

// match relative data. which starts at the document root. In your case you are trying to locate using
//li[starts-with(#class, '_lessons--row-')]
So it will return all the match in your html. If you want to locate some specific portion of element with class have start text_lessons--row- . You have to make your xpath more specific.
e.g
//div[#id='someid']//li[starts-with(#class, '_lessons--row-')]

I had a similar case, but . before // didn't help me. Just added findElements(By.xpath("your_xpath")).stream().filter(WebElement::isDisplayed).toList() as a workaround.

Related

How to get all the xpath of the elements a Web Page using Robot Framework?

I'm using Robotframework to automate tests, it uses the Selenium2 Library and gives the opportunity to extend many libraries (Java, Python, AngularJS, etc.).
Here's my question.
Is there a way to get all the xpath of elements displayed on a page that match a certain criteria?
Thanks in Advance,
I'll answer the question the 2 ways I understand it - at least one should be the looked for ;)
Presuming the xpath is //div - e.g. "all div elements"
1) To count how many matching elements are there:
${count}= Get Matching Xpath Count //div # note there's no xpath= prefix
As pointed out in the comments, the return value of Get Matching Xpath Count is of a String type, so if you want to use it for some numerical comparisons, you'd better cast it to int:
${count}= Convert To Integer ${count}
2) To get each element matching that xpath, and do something with it
${matched elements}= Get Webelements xpath=//div
:FOR ${element} IN #{matched elements}
\ ${text}= Get Text ${element} # will get the text of each matched node
\ Log ${text}

Getting WebElement by Text using XPath in Selenium test

I would like to find any WebElement based on text using XPath.
WebElement that I am interested to find,
Its HTML,
Basically my WebElement that I am trying to retrieve by Text contains an input element.
I currently use,
driver.findElement(By.xpath("//*[normalize-space(text()) = 'Own Hotel']"));
which does not find the WebElement above, but it usually works to retrieve all other web elements.
Even,
By.xpath("//*[contains(text(),'Own Hotel')]")
did not give me any results. Although I am interested in exact text match.
I am looking for a way to find web element by text immaterial of the elements that are present inside the web element. If text matches, it should return the WebElement.
Thanks!
It seems text is wrapped inside a label and not input. Try this
driver.findElement(By.xpath(".//label[text()[normalize-space() = 'Own Hotel']]"));
There is nice explanation about this xpath pattern here
In the HTML below:
The innerText Own Hotel within the <input> node contains a lot of white-space characters in the beginning as well at the end. Due to the presence of these leading and trailing white-space characters you can't use the location path text() as:
text() selects all text node children of the context node
As an alternative, you need to use the String Function string normalize-space(string?) as follows:
driver.findElement(By.xpath("//*[normalize-space()='Own Hotel']"));
However, it would a better idea to make your search a bit more granular adding the tagName and preferably an unque attribute as follows:
Using tagName and normalize-space():
driver.findElement(By.xpath("//input[normalize-space()='Own Hotel']"));
Using tagName, and normalize-space():
driver.findElement(By.xpath("//input[#name='ownHotel' and normalize-space()='Own Hotel']"));
References
you can find a couple of relevant discussions using normalize-space() in:
How to click on a link with trailing white-space characters on a web page using Selenium?
How to locate and click the element when the innerText contains leading and trailing white-space characters using Selenium and Python
How to click on the button when the textContext contains leading and trailing white-space characters using Selenium and Python

How to determine whether XPath targets (returns) attribute or element?

In Java, how do you properly determine if XPath selector targets attribute or element?
To explain the issue: I need to get text from WebDriver's WebElement. Either innerText of the element or it's attribute depending on the XPath. Unfortunately each extraction is done differently (see below) so I have to determine first what the intended target is, element or attribute:
String getStringValue(String selector, WebElement context) {
if(targetsAttribute(selector) {
WebElement node = context.findElement(new By.xpath(elemPart(selector)));
return node.getAttribute(attrName(selector));
} else {
return context.findElement(new By.xpath(selector)).getText();
}
};
I'm looking for implementation of targetsAttribute, elemPart and attrName methods. Currently I use regex's:
Pattern ATTR_PAT = Pattern.compile("^.*/#([^/]+)$");
Pattern ELEM_PAT = Pattern.compile("^(.*)/#[^/]+$");
But I find this approach ugly and non-systematic. It doesn't match attribute:: for example. Is there some way to do this using some standard library or so?
NOTE: I'm actually trying to solve similar problem as in following question, only going a bit higher:
How to get the value of an attribute using XPath
You might be able to use the XPath expression parser that's part of Saxon XSLT/XQuery processor.
ExpressionParser's parseExpression() method should be able to give you the information you need.
If you do figure it out, please post your code (as an answer) because I don't know that anybody else has posted a solution.
Edit:
Actually, it's impossible to construct an algorithm that will correctly answer, for every XPath expression, whether it will select an element or an attribute. This is because the type of result returned by an XPath expression can depend on the input. E.g. the XPath expression
//foo | //bar/#baz
could return elements, attributes, both, or neither, depending on what elements and attributes exist in the document.
However, using the parsing tools mentioned above would probably give you your best chance at figuring out, for a subset of XPath expressions, whether they can return an attribute or not.
It seems to me that the inability to get the string value of an XPath expression, regardless of whether it selects an element or an attribute, is a serious shortcoming in the WebDriver API. Unless it provides that ability in some other way that I'm not aware of.
The lack of a node-agnostic means to address text content is a problem in many (if not all!) XPath APIs. And, as already indicated, there is no completely general way to determine in advance whether an XPath expression selects attributes or elements, as it could select both, with a disjunctive combination.
If you can rule out disjunctions (or treat each piece separately) then, heuristically, it all depends on what follows the final slash in the expression: if the remainder starts with '#' (or 'attribute::'), you're selecting an attribute; otherwise, an element. This is not bullet-proof, but from experience I've found that this is good enough in practice. Your heuristic approach is as good as any.

How to getText() for XPath with attribute 'display:none'

I would like to use getText() for one XPath, need text what is there.
//span(contains(#style,'display:none'))
XPath is working tested in firebug, I've tried getText, getAttribute, so far no luck
It's a little hard to say without the exact HTML, which you have not specified in your question...
To begin with, you need to change this:
"//span(contains(#style,'display:none'))"
To this:
"//span[contains(#style,'display:none')]"
UPDATE:
Alternatively, since the span element is not visible, you might be able to do it with:
String innerHTML = elem.getAttribute("innerHTML");
Where elem is the parent node of the span element.
Then, in order to get the actual text, you will need to parse the innerHTML string.
Because the element is invisible (it has display:none), Selenium cannot natively interact with it. You need cast your driver to JavascriptExecutor, then execute the following javascript:
$x("//span(contains(#style,'display:none'))")[0].text
The [0] returns the 1st element returned by the xpath.
This will return the inner text of the element.

Standard xpath syntax to find all nodes with a given name (e.g. "//nodeName") fails

I've loaded up an XML document and I'm attempting to use xpath to find all nodes with the name "CodeList". For whatever reason, the xpath expression //CodeList provides 0 nodes, but the xpath expression /.//CodeList provides me with the list of correctly identified nodes. Reading through various tutorials on the Internet, //CodeList should be the correct syntax to do what I want.
I'm not certain as to why this is happening. The xpath expression . and /. return the same node, which seems to be the document (getNodeName returns "#document").
Someone suggested that the libraries in my classpath could be the source of the problem.
So far, the only XML-related libraries that are dependencies are:
xmlbeans-2.3.0
xml-apis-1.3.04
xalan-2.7.1
xercesImpl-2.9.1
/CodeList and /.//CodeList should both return exactly the same result. If they don't, it's a bug. Both should return all the CodeList elements in no namespace. If your elements are all in a (default) namespace, both expressions should return nothing.
try
"//CodeList/*/text()"
and you'll have all child nodes in lines

Categories