Selenium JavascriptExecutor - Unexpected token at javascript algorithm - java

I try to execute this java code
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement hoverElement = wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath("//div[#id = 'demo']")));
//trigger mouseover on hoverElement
//return innerHTML of element which appear
String jsAlg = "" +
"if(document.createEvent){" +
"var evObj = document.createEvent('MouseEvents');" +
"evObj.initEvent('mouseover', true, false);" +
"arguments[0].dispatchEvent(evObj);" +
"}else if(document.createEventObject){" +
"arguments[0].fireEvent('onmouseover');" +
"}" +
"var target = new XPathEvaluator().createExpression(//div[#id = 'target'])" +
".evaluate(document, XPathResult.FIRST_ORDERED_NODE_TYPE)" +
".singleNodeValue" +
"return target.innerHTML;";
String targetHTML = (String)((JavascriptExecutor)driver).executeScript(jsAlg, hoverElement);
System.out.println(targetHTML);
I try to execute this js on this html
<html>
<head>
</head>
<body>
<div id="demo" onmouseover="mouseOver()" onmouseout="mouseOut()">Mouse over here</div>
<script>
var node = document.createElement("div");
node.id = "target";
node.innerHTML = "mouse over active";
function mouseOver() {
document.body.appendChild(node);
}
function mouseOut() {
document.body.removeChild(node);
}
</script>
</body>
</html>
I get an error when try to execute jsAlg: javascript error: Unexpected token '}'
What is wrong at jsAlg?
Edit 1
The problem is at var target = ....
I replaced that with var target = document.getElementById('target'); and work.
But I need to use XPathEvaluator because, I execute this js in other case, where target don't have an id and can identify it with xpath.
Edit 2(I found the real problem)
The problem was at .createExpression(//div[#id = 'target'])
It should be .createExpression(\"//div[#id = 'target']\")
Parameter should be between "

Related

Parsing html in Jsoup

I am trying to parse html tags here using jsoup. I am new to jsoup. Basically I need to parse the tags and get the text inside those tags and apply the style mentioned in the class attribute.
I am creating a SpannableStringBuilder for that I can create substrings, apply styles and append them together with texts that have no styles.
String str = "There are <span class='newStyle'> two </span> workers from the <span class='oldStyle'>Front of House</span>";
SpannableStringBuilder text = new SpannableStringBuilder();
if (value.contains("</span>")) {
Document document = Jsoup.parse(value);
Elements elements = document.getElementsByTag("span");
if (elements != null) {
int i = 0;
int start = 0;
for (Element ele : elements) {
String styleName = type + "." + ele.attr("class");
text.append(ele.text());
int style = context.getResources().getIdentifier(styleName, "style", context.getPackageName());
text.setSpan(new TextAppearanceSpan(context, style), start, text.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
text.append(ele.nextSibling().toString());
start = text.length();
i++;
}
}
return text;
}
I am not sure how I can parse the strings that are not between any tags such as the "There are" and "worker from the".
Need output such as:
- There are
- <span class='newStyle'> two </span>
- workers from the
- <span class='oldStyle'>Front of House</span>
Full answer: you can get the text outside of the tags by getting childNodes(). This way you obtain List<Node>. Note I'm selecting body because your HTML fragment doesn't have any parent element and parsing HTML fragment with jsoup adds <html> and <body> automatically.
If Node contains only text it's of type TextNode and you can get the content using toString().
Otherwise you can cast it to Element and get the text usingelement.text().
String str = "There are <span class='newStyle'> two </span> workers from the <span class='oldStyle'>Front of House</span>";
Document doc = Jsoup.parse(str);
Element body = doc.selectFirst("body");
List<Node> childNodes = body.childNodes();
for (int i = 0; i < childNodes.size(); i++) {
Node node = body.childNodes().get(i);
if (node instanceof TextNode) {
System.out.println(i + " -> " + node.toString());
} else {
Element element = (Element) node;
System.out.println(i + " -> " + element.text());
}
}
output:
0 ->
There are
1 -> two
2 -> workers from the
3 -> Front of House
By the way: I don't know how to get rid of the first line break before There are.

Want to Retrieve Xpath of Given WebElement

Using Selenium WebDriver, I am having a list of all web elements in the page. I want to write one function which will return me the XPath string of passed element.
Call for Function will be like:-
String XpathOfElement = myWebDriver.getXpath(My_Web_Element)
Hint :- I think we can use javascript(using JavaScriptExecuter). But not familiar with javascript.
Check this post, I wrote code to get an absolute XPath.
public static String getAbsoluteXPath(WebElement element)
{
return (String) ((JavascriptExecutor) driver).executeScript(
"function absoluteXPath(element) {"+
"var comp, comps = [];"+
"var parent = null;"+
"var xpath = '';"+
"var getPos = function(element) {"+
"var position = 1, curNode;"+
"if (element.nodeType == Node.ATTRIBUTE_NODE) {"+
"return null;"+
"}"+
"for (curNode = element.previousSibling; curNode; curNode = curNode.previousSibling) {"+
"if (curNode.nodeName == element.nodeName) {"+
"++position;"+
"}"+
"}"+
"return position;"+
"};"+
"if (element instanceof Document) {"+
"return '/';"+
"}"+
"for (; element && !(element instanceof Document); element = element.nodeType == Node.ATTRIBUTE_NODE ? element.ownerElement : element.parentNode) {"+
"comp = comps[comps.length] = {};"+
"switch (element.nodeType) {"+
"case Node.TEXT_NODE:"+
"comp.name = 'text()';"+
"break;"+
"case Node.ATTRIBUTE_NODE:"+
"comp.name = '#' + element.nodeName;"+
"break;"+
"case Node.PROCESSING_INSTRUCTION_NODE:"+
"comp.name = 'processing-instruction()';"+
"break;"+
"case Node.COMMENT_NODE:"+
"comp.name = 'comment()';"+
"break;"+
"case Node.ELEMENT_NODE:"+
"comp.name = element.nodeName;"+
"break;"+
"}"+
"comp.position = getPos(element);"+
"}"+
"for (var i = comps.length - 1; i >= 0; i--) {"+
"comp = comps[i];"+
"xpath += '/' + comp.name.toLowerCase();"+
"if (comp.position !== null) {"+
"xpath += '[' + comp.position + ']';"+
"}"+
"}"+
"return xpath;"+
"} return absoluteXPath(arguments[0]);", element);
}
This code works perfectly.
public String getXpath(WebElement ele) {
String str = ele.toString();
String[] listString;
if(str.contains("xpath")
listString = str.split("xpath:");
else if(str.contains("id")
listString = str.split("id:");
String last = listString[1].trim();
return last.substring(0, last.length() - 1);
}
This above function works only if the WebElement has xpath. Suppose your element has class, then use if-else concept with "class:" as split expression.
Almost any element in DOM can have a lot of valid xPathes. For example input field on Google search page can be found as: //*[#id='lst-ib'] //*[#class='gsfi'][1] //body//div//input[3]...
Which one do you expect to get?
Actually google has this algorithm in chrome. We can copy xpath of the element and in most cases it is awfull.
So it's possible to do, and if it's really vital for you look at NHtmlUnit - you can get dom of the page, find your element there and go up to root element adding tags to path string. I guess, it's poosible to get something like //body/div/div[2]/div[3]/... But why?

How to get anchor tag href and anchor tag text inside a div using Selenium in Java

My HTML code consists of multiple divs. Inside each div is a list of anchor tags. I need to fetch the href values and text values of the anchor tags that are in the sub-container div. I'm using Selenium to get the HTML code of the webpage.
HTML code:
<body>
<div id="main-container">
One
Two
Three
<div id="sub-container">
Abc
Xyz
Pqr
</div>
</div>
</body>
Java code:
List<WebElement> list = driver.findElements(By.xpath("//*[#href]"));
for (WebElement element : list) {
String link = element.getAttribute("href");
System.out.println(e.getTagName() + "=" + link);
}
Output:
a=www.one.com
a=www.two.com
a=www.three.com
a=www.abc.com
a=www.xyz.com
a=www.pqr.com
Output I need:
a=www.abc.com , Abc
a=www.xyz.com , Xyz
a=www.pqr.com , Pqr
Try this,
List<WebElement> list = driver.findElements(By.xpath("//div[#id='sub-container']/*[#href]"));
for (WebElement element : list) {
String link = element.getAttribute("href");
System.out.println(element.getTagName() + "=" + link +", "+ element.getText());
}
You can use element.getText() to get the link text.
If you only want to select the links in the sub-container, you can adjust your xPath:
//*[#id="sub-container"]/a
Pretty simple, try as below:
`List<WebElement> list = driver.findElements(By.xpath("//div[#id='sub-container']/a"));
for (WebElement element : list) {
String link = element.getAttribute("href");
String text = element.getText();
System.out.println(e.getTagName() + "=" + link + ", " + text);
}
if id sub-container is unique, just use the below line
driver.findElements(By.cssSelector("div#sub-container>a"));
thanks

Update a tag name along with its value

I am trying to replace html tags with updated values. I had tried using JSOUP but could not work out a way yet.
The functionality:
if (webText.contains("a href")) {
// Parse it into jsoup
Document doc = Jsoup.parse(webText);
// Create an array to tackle every type individually as wrap can
// affect whole body types otherwises.
Element[] array = new Element[doc.select("a").size()];
for (int i = 0; i < doc.select("a").size(); i++) {
if (doc.select("a").get(i) != null) {
array[i] = doc.select("a").get(i);
}
}
for (int i = 0; i < array.length; i++) {
if (array[i].toString().contains("http")) {
Log.e("Link", array[i].toString());
Pattern p = Pattern.compile("href=\"(.*?)\"");
Matcher m = p.matcher(array[i].toString());
String url = null;
if (m.find()) {
url = m.group(1); // this variable should contain the link URL
Log.e("Link Value", url);
array[i] = array[i].wrap("<a href='"+url+"' class='link'></a>");
}
}
else {
Log.e("Favourite", array[i].toString());
Pattern p = Pattern.compile("href=\"(.*?)\"");
Matcher m = p.matcher(array[i].toString());
String url = null;
if (m.find()) {
url = m.group(1); // this variable should contain the link URL
Log.e("Favourite Value", url);
array[i] = array[i].wrap("<a href='"+url+"' class='favourite'></a>");
//array[i] = array[i].replaceWithreplaceWith("","");
}
}
}
Element element = doc.body();
Log.e("From element html *************** ", " " + element.html());
String currentHtml = wrapImgWithCenter(element.html());
Log.e("currentHtml", currentHtml);
listOfElements = currentHtml;
}
This array[i] = array[i].wrap("<a href='"+url+"' class='favourite'></a>"); is basically wrapping the existing tags with the new value. But I do not want that to happen. I want to replace the tags completely with something like:
"<a href='"+url+"' class='favourite'>+url+"</a>";
Input:
<html>
<head></head>
<body>
<p dir="ltr"><font color="#009a49">Frank Frank</font> <font color="#0033cc">http://yahoo.co.in</font></p>
<br />
<br />
</body>
</html>
Expected output:
<html>
<head></head>
<body>
<p dir="ltr"><font color="#009a49">Frank Frank</font> <font color="#0033cc">http://yahoo.co.in</font></p>
<br />
<br />
</body>
</html>
I have tried using replaceWith but was unsuccessful. You can still find it commented out in the source code provided above. Please tell me where am I going wrong? What should I do to update the tags?
P.S.: The input might be variable with some more or less tags.
You can use the replaceWith method of class Element. I've cleared your code a little bit. Removed the arrays and used the provided lists wherever possible. Moreover you don't need regex to get the href attribute (or any other attribute for that matter) when you've already parsed the html. Check it out and inform me if you need further assistance.
import org.jsoup.Jsoup;
import org.jsoup.nodes.Attributes;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.parser.Tag;
import org.jsoup.select.Elements;
public class Main {
public static void main(String[] args) throws Exception {
String webText =
"<html>" +
"<head></head>" +
"<body>" +
"<p dir=\"ltr\">" +
"" +
"<font color=\"#009a49\">Frank Frank</font>" +
"" +
"<font color=\"#0033cc\">http://yahoo.co.in</font>" +
"</p>" +
"</body>" +
"</html>";
if (webText.contains("a href")) {
// Parse it into jsoup
Document doc = Jsoup.parse(webText);
Elements links = doc.select("a");
for (Element link : links) {
if (link.attr("href").contains("http")) {
System.out.println("Link: " + link.toString());
String url = link.attr("href");
if (url != null) {
System.out.println("Link Value: " + url);
Attributes attributes = new Attributes();
attributes.put("href", url);
attributes.put("class", "link");
link.replaceWith(new Element(Tag.valueOf("a"), "", attributes).insertChildren(0, link.childNodes()));
}
} else {
System.out.println("Favourite: " + link.toString());
String url = link.attr("href");
if (url != null) {
System.out.println("Favourite Value: " + url);
Attributes attributes = new Attributes();
attributes.put("href", url);
attributes.put("class", "favourite");
link.replaceWith(new Element(Tag.valueOf("a"), "", attributes).insertChildren(0, link.childNodes()));
}
}
}
Element element = doc.body();
System.out.println("From element html *************** "+ element.html());
}
}
}
Input
<p dir="ltr">
<font color="#009a49">Frank Frank</font>
<font color="#0033cc">http://yahoo.co.in</font>
</p>
Output
<p dir="ltr">
<font color="#009a49">Frank Frank</font>
<font color="#0033cc">http://yahoo.co.in</font>
</p>
Input
<p dir="ltr">
<font color="#009a49">Frank Frank</font>
<font color="#0033cc">http://yahoo.co.in</font>
</p>
Output
<p dir="ltr">
<font color="#009a49">Frank Frank</font>
<font color="#0033cc">http://yahoo.co.in</font>
</p>

How to use JSoup to get hyperlink href?

I have the following jsFiddle
http://jsfiddle.net/B5zvV/
I am trying to use JSoup to obtain the value of the hyperlink's href string on Line 238:
<a href="/chain/admin/config/editRepository.action?planKey=AB-CSD&repositoryId=28049450">
Hence, the desired result would be to obtain a String with a value of:
/chain/admin/config/editRepository.action?planKey=AB-CSD&repositoryId=28049450
Here's my code:
Document doc = Jsoup.connect("http://myapp.example.com/fizz.html").get()
Elements elems = doc.getElementsByAttributeValueContaining("href", "repositoryId")
When I run this, the value of elems is empty: why, and what do I need to do to get the desired String?
The getElementsByAttributeValueContaining() method will return multiple values in this case because many hrefs has repositoryId. If you are particular about line 238 then that a is enclosed inside an li with class item item-default. There is only one such li and two a tags inside it. Just take the first one like
String html = "<li class=\"item item-default\" data-item-id=\"28049450\" id=\"item-28049450\">"
+ "<a href=\"/chain/admin/config/editRepository.action?planKey=AB-CSD&repositoryId=28049450\">"
+ "<h3 class=\"item-title\">MCAppRepo <span class=\"item-default-marker grey\">(default)</span></h3>"
+ "</a>"
+ "<a href=\"/chain/admin/config/confirmDeleteRepository.action?planKey=AB-CSD&repositoryId=28049450\" class=\"delete\" title=\"Remove repository\">"
+ "<span class=\"assistive\">Delete</span>"
+ "</a>"
+ "</li>";
Document doc = Jsoup.parse(html);
Elements elems = doc.select("li.item.item-default > a");
System.out.println(elems.first().attr("href"));

Categories