Is there a way to get element by XPath using JavaScript in Selenium WebDriver?

JavascriptSeleniumSelenium WebdriverXpathdocument.evaluate

Javascript Problem Overview


I am looking for something like:

getElementByXpath(//html[1]/body[1]/div[1]).innerHTML

I need to get the innerHTML of elements using JS (to use that in Selenium WebDriver/Java, since WebDriver can't find it itself), but how?

I could use ID attribute, but not all elements have ID attribute.

[FIXED]

I am using jsoup to get it done in Java. That works for my needs.

Javascript Solutions


Solution 1 - Javascript

You can use document.evaluate:

> Evaluates an XPath expression string and returns a result of the > specified type if possible.

It is w3-standardized and whole documented: https://developer.mozilla.org/en-US/docs/Web/API/Document.evaluate

function getElementByXpath(path) {
  return document.evaluate(path, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
}

console.log( getElementByXpath("//html[1]/body[1]/div[1]") );

<div>foo</div>

https://gist.github.com/yckart/6351935

There's also a great introduction on mozilla developer network: https://developer.mozilla.org/en-US/docs/Introduction_to_using_XPath_in_JavaScript#document.evaluate


Alternative version, using XPathEvaluator:

function getElementByXPath(xpath) {
  return new XPathEvaluator()
    .createExpression(xpath)
    .evaluate(document, XPathResult.FIRST_ORDERED_NODE_TYPE)
    .singleNodeValue
}

console.log( getElementByXPath("//html[1]/body[1]/div[1]") );

<div>foo/bar</div>

Solution 2 - Javascript

In Chrome Dev Tools you can run the following:

$x("some xpath")

Solution 3 - Javascript

For something like $x from chrome command line api (to select multiple elements) try:

var xpath = function(xpathToExecute){
  var result = [];
  var nodesSnapshot = document.evaluate(xpathToExecute, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null );
  for ( var i=0 ; i < nodesSnapshot.snapshotLength; i++ ){
    result.push( nodesSnapshot.snapshotItem(i) );
  }
  return result;
}

This MDN overview helped: https://developer.mozilla.org/en-US/docs/Introduction_to_using_XPath_in_JavaScript

Solution 4 - Javascript

To identify a WebElement using [tag:xpath] and [tag:javascript] you have to use the evaluate() method which evaluates an xpath expression and returns a result.


document.evaluate()

document.evaluate() returns an XPathResult based on an XPath expression and other given parameters.

The syntax is:

var xpathResult = document.evaluate(
  xpathExpression,
  contextNode,
  namespaceResolver,
  resultType,
  result
);

Where:

  • xpathExpression: The string representing the XPath to be evaluated.
  • contextNode: Specifies the context node for the query. Common practice is to pass document as the context node.
  • namespaceResolver: The function that will be passed any namespace prefixes and should return a string representing the namespace URI associated with that prefix. It will be used to resolve prefixes within the XPath itself, so that they can be matched with the document. null is common for HTML documents or when no namespace prefixes are used.
  • resultType: An integer that corresponds to the type of result XPathResult to return using named constant properties, such as XPathResult.ANY_TYPE, of the XPathResult constructor, which correspond to integers from 0 to 9.
  • result: An existing XPathResult to use for the results. null is the most common and will create a new XPathResult

Demonstration

As an example the Search Box within the Google Home Page which can be identified uniquely using the xpath as //*[@name='q'] can also be identified using the [tag:google-chrome-devtools] Console by the following command:

$x("//*[@name='q']")

Snapshot:

googlesearchbox_xpath

The same element can can also be identified using document.evaluate() and the xpath expression as follows:

document.evaluate("//*[@name='q']", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;

Snapshot:

document_evalute_xpath

Solution 5 - Javascript

You can use javascript's document.evaluate to run an XPath expression on the DOM. I think it's supported in one way or another in browsers back to IE 6.

MDN: https://developer.mozilla.org/en-US/docs/Web/API/Document/evaluate

IE supports selectNodes instead.

MSDN: https://msdn.microsoft.com/en-us/library/ms754523(v=vs.85).aspx

Solution 6 - Javascript

To direct to the point , you can easily use xapth .The exact and simple way to do this using the below code . Kindly try and provide feedback .Thank you .

JavascriptExecutor js = (JavascriptExecutor) driver;

    //To click an element 
    WebElement element=driver.findElement(By.xpath(Xpath));
    js.executeScript(("arguments[0].click();", element);
    
    //To gettext
    
    String theTextIWant = (String) js.executeScript("return arguments[0].value;",driver.findElement(By.xpath("//input[@id='display-name']")));

Further readings - https://medium.com/@smeesheady/webdriver-javascriptexecutor-interact-with-elements-and-open-and-handle-multiple-tabs-and-get-url-dcfda49bfa0f

Solution 7 - Javascript

Although many browsers have $x(xPath) as a console built-in, here's an aggregation of the useful-but-hardcoded snippets from Introduction to using XPath in JavaScript ready for use in scripts:

Snapshot

This gives a one-off snapshot of the xpath result set. Data may be stale after DOM mutations.

const $x = xp => {
  const snapshot = document.evaluate(
    xp, document, null, 
    XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null
  );
  return [...Array(snapshot.snapshotLength)]
    .map((_, i) => snapshot.snapshotItem(i))
  ;
};

console.log($x('//h2[contains(., "foo")]'));

<h2>foo</h2>
<h2>foobar</h2>
<h2>bar</h2>

First ordered node

const $xOne = xp => 
  document.evaluate(
    xp, document, null,
    XPathResult.FIRST_ORDERED_NODE_TYPE, null
  ).singleNodeValue
;

console.log($xOne('//h2[contains(., "foo")]'));

<h2>foo</h2>
<h2>foobar</h2>
<h2>bar</h2>

Iterator

> Note however, that if the document is mutated (the document tree is modified) between iterations that will invalidate the iteration and the invalidIteratorState property of XPathResult is set to true, and a NS_ERROR_DOM_INVALID_STATE_ERR exception is thrown.

function *$xIter(xp) {
  const iter = document.evaluate(
    xp, document, null, 
    XPathResult.ORDERED_NODE_ITERATOR_TYPE, null
  );

  for (;;) {
    const node = iter.iterateNext();
    
    if (!node) {
      break;
    }
    
    yield node;
  }
}

// dump to array
console.log([...$xIter('//h2[contains(., "foo")]')]);

// return next item from generator
const xpGen = $xIter('//h2[text()="foo"]');
console.log(xpGen.next().value);

<h2>foo</h2>
<h2>foobar</h2>
<h2>bar</h2>

Solution 8 - Javascript

Assuming your objective is to develop and test your xpath queries for screen maps. Then either use Chrome's developer tools. This allows you to run the xpath query to show the matches. Or in Firefox >9 you can do the same thing with the Web Developer Tools console. In earlier version use x-path-finder or Firebug.

Solution 9 - Javascript

public class JSElementLocator {
	
	@Test
	public void locateElement() throws InterruptedException{
		WebDriver driver = WebDriverProducerFactory.getWebDriver("firefox");

		driver.get("https://www.google.co.in/");


		WebElement searchbox = null;
		
		Thread.sleep(1000);
		searchbox = (WebElement) (((JavascriptExecutor) driver).executeScript("return document.getElementById('lst-ib');", searchbox));
		searchbox.sendKeys("hello");
	}
}

Make sure you are using the right locator for it.

Solution 10 - Javascript

**Different way to Find Element:**
    
IEDriver.findElement(By.id("id"));
IEDriver.findElement(By.linkText("linkText"));
IEDriver.findElement(By.xpath("xpath"));
    
IEDriver.findElement(By.xpath(".//*[@id='id']"));
IEDriver.findElement(By.xpath("//button[contains(.,'button name')]"));
IEDriver.findElement(By.xpath("//a[contains(.,'text name')]"));
IEDriver.findElement(By.xpath("//label[contains(.,'label name')]"));
    
IEDriver.findElement(By.xpath("//*[contains(text(), 'your text')]");
    
Check Case Sensitive:
IEDriver.findElement(By.xpath("//*[contains(lower-case(text()),'your text')]");
     
For exact match: 
IEDriver.findElement(By.xpath("//button[text()='your text']");
    
**Find NG-Element:**
    
Xpath == //td[contains(@ng-show,'childsegment.AddLocation')]
CssSelector == .sprite.icon-cancel

Solution 11 - Javascript

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;

System.setProperty("webdriver.chrome.driver", "path of your chrome exe");
		WebDriver driver = new ChromeDriver();
		driver.manage().window().maximize();
        driver.get("https://www.google.com");

            driver.findElement(By.xpath(".//*[@id='UserName']")).clear();
			driver.findElement(By.xpath(".//*[@id='UserName']")).sendKeys(Email);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionpManView Question on Stackoverflow
Solution 1 - JavascriptyckartView Answer on Stackoverflow
Solution 2 - JavascriptDmitry SemenyukView Answer on Stackoverflow
Solution 3 - JavascriptJayView Answer on Stackoverflow
Solution 4 - Javascriptundetected SeleniumView Answer on Stackoverflow
Solution 5 - JavascriptRobGView Answer on Stackoverflow
Solution 6 - JavascriptSameera De SilvaView Answer on Stackoverflow
Solution 7 - JavascriptggorlenView Answer on Stackoverflow
Solution 8 - JavascriptMartin SpamerView Answer on Stackoverflow
Solution 9 - JavascriptPrerit JainView Answer on Stackoverflow
Solution 10 - JavascriptAlok PatelView Answer on Stackoverflow
Solution 11 - JavascriptDharit MehtaView Answer on Stackoverflow