Reputation: 29669
I am trying to create a Selenium getText() method that gets either the node text OR gets the node+child text of an element. By default, the Selenium behavior seems to use the Xpath .//string() method of getting text and including the text of immediate children. I want to take advantage of XPaths power to enable me to get the text in a more targeted way. My question is: am I misunderstanding this or is there a better way to accomplish this?
public String getText(By locationOfText, boolean childText)
{
By locator = null;
if ( childText)
{
locator = ByChained( locationOfText, By.xpath(".//string()"));
} else {
locator = ByChained( locationOfText, By.xpath(".//text()"));
}
JavascriptExecutor jse = (JavascriptExecutor)driver;
String elementText = jse.executeScript("document.evaluate(locator, document.body, null,
XPathResult.STRING_TYPE, null);");
return elementText;
}
Here is an HTML snippet:
<h5 class="class-name clearfix">Inner Text
<a class="info-link class-description" href="#">i</a>
</h5>
The problem is that I get the text Inner Texti when I use Selenium to do a text call like this:
driver.findElement(".//h5").getText();
My expectation was to retrieve the value Inner Text . By creating the method above, I hope to call it like so:
String text = elementHelper.getText(By.xpath(".//h5"),false);
Upvotes: 3
Views: 3015
Reputation: 151401
string()
is an XPath 2.0 construct but most browsers (if not all), only support XPath 1.0. Moreover, I'm not that fond of rushing to XPath for querying the DOM tree. XPath evaluation has a significant performance overhead. So adapting my answer here, I would suggest:
public String getText(By locationOfText, boolean childText)
{
WebElement el = driver.findElement(locationOfText);
if (childText)
{
return el.getText();
}
JavascriptExecutor jse = (JavascriptExecutor) driver;
return jse.executeScript(
"var parent = arguments[0]; "+
"var child = parent.firstChild; "+
"var ret = ""; "+
"while(child) { "+
" if (child.nodeType === Node.TEXT_NODE) "+
" ret += child.textContent; "+
" child = child.nextSibling; "+
"} "+
"return ret;", el);
}
The locationOfText
parameter could be any By
method that Selenium supports.
In your code you use ByChained
for location
, which presumably you'd want to pass to executeScript
but forgot to do. I cannot see how this would work, even if you added location
to your executeScript
call (and fixed the script to grab arguments[0]
). ByChained
would support things like mixing a CSS selector with an XPath, etc. Selenium can presumably resolve the combination by performing multiple searches but there is no way the XPath engine of a browser will accept some sort of combination of CSS and XPath.
Upvotes: 3