Sandesh Sawant
Sandesh Sawant

Reputation: 15

Difference between 3 different Xpaths producing same results

I am trying to locate the element <a>.

HTML:

<html><head></head><body>
<a href="https://www.google.com">Click Here!</a>
</body></html>

Below is the Selenium code using Xpath producing same results:

driver.findElement(By.xpath("self::node()/child::node()/child::body/child::a")).click();    //Statement1
driver.findElement(By.xpath("/child::node()/child::body/child::a")).click();    //Statement2
driver.findElement(By.xpath("child::node()/child::body/child::a")).click(); //Statement3

My understanding:

In Statement1, it mentions the initial context node as the self::node. Here, we are passing our entire HTMLDocument as the self::node(). So, our initial context node is set to entire HTMLDocument(which is also called as document root node(/)). So, our initial context node is set to document root node(/)
In Statement2, it mentions the initial context node absolutely as the document root node(/).
But in Statement3, the initial context node is not mentioned.

So, does it mean that if we do not mention the initial context node, then will it be set to document root node(/) by default ?

Please help to improve my understanding.

Upvotes: 0

Views: 80

Answers (1)

Alexey R.
Alexey R.

Reputation: 8676

Your 1 and 3 statements are the same from the "context" standpoint (self and child are both xpath axes). Both have root of the document as the context (in Selenium it is called SearchContext).

The context is root in that case because you lookup elements right within a driver. If you will have a WebElement and try to look up elements inside that element your context won't be root for 1 and 3 statements.

Below is some more detailed explanation..

Assume we have test.html with the following content:

<A val="success A">
  <B val="success B"/>
</A>

And the test like this:

@Test
public void test(){
    driver.get("file:///path_to_page/test.hml");
    WebElement a = driver.findElement(By.xpath("html/body/A")); // (1, 2)
    System.out.println(a.getAttribute("val"));
    try{
        System.out.println(driver.findElement(By.xpath("body/A/B")).getAttribute("val")); // (3)
    }catch (NoSuchElementException e){
        System.out.println("body/A/B cannot be found as the context is root");
    }
    WebElement b = a.findElement(By.xpath("B")); // (4)
    System.out.println(b.getAttribute("val"));
    System.out.println(b.findElement(By.xpath("/html/body/A")).getAttribute("val")); // (5)
}

Here are few remarkable points:

  1. Despite our file has the root A, browser automatically adds html tags to make the html file valid. So it adds html node and body node
  2. Considering the previous point we start from accessing html/body/A which has the root context
  3. Then we make sure that we cannot find B using the path body/A/B since the context is still root.
  4. Then we can see that we can find B in the context of previously located A.
  5. The final thing is that we are looking up /html/body/A within the context of B. Despite we use the B as search context we still can find the element because we start the path from / which means root and ignores any search context.

Upvotes: 1

Related Questions