152

I have a certain element that I can select with Selenium 1.

Unfortunately I need to click the parent element to get the desired behaviour. The element I can easily locate has attribute unselectable, making it dead for clicking. How do I navigate upwards with XPath?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
f l
  • 1,684
  • 2
  • 10
  • 11

8 Answers8

232

There are a couple of options there. The sample code is in Java, but a port to other languages should be straightforward.

Java:

WebElement myElement = driver.findElement(By.id("myDiv"));
WebElement parent = (WebElement) ((JavascriptExecutor) driver).executeScript(
                                   "return arguments[0].parentNode;", myElement);

XPath:

WebElement myElement = driver.findElement(By.id("myDiv"));
WebElement parent = myElement.findElement(By.xpath("./.."));

Obtaining the driver from the WebElement

Note: As you can see, for the JavaScript version you'll need the driver. If you don't have direct access to it, you can retrieve it from the WebElement using:

WebDriver driver = ((WrapsDriver) myElement).getWrappedDriver();
Steven
  • 5,134
  • 2
  • 27
  • 38
acdcjunior
  • 132,397
  • 37
  • 331
  • 304
  • 49
    And if you want to navigate to the grandparent, use By.Xpath("../.."). – Monsignor Aug 21 '13 at 15:19
  • @Monsignor Works just like file paths... or URL paths: https://stackoverflow.com/questions/8577636/../../questions/8577636/select-parent-element-of-known-element-in-selenium#comment26957658_18001659 – jpaugh Jan 24 '18 at 04:40
  • 2
    None of these XPaths are correct for use with Selenium. One needs to use `By.xpath(“./..”)` to correctly walk up the DOM tree when using `element.findElement`. The leading “./“ is required to set the context node. – JimEvans Nov 08 '18 at 15:29
58

Little more about XPath axes

Lets say we have below HTML structure:

<div class="third_level_ancestor">
    <nav class="second_level_ancestor">
        <div class="parent">
            <span>Child</span>
        </div>
    </nav>
</div>
  1. //span/parent::* - returns any element which is direct parent.

In this case output is <div class="parent">

  1. //span/parent::div[@class="parent"] - returns parent element only of exact node type and only if specified predicate is True.

Output: <div class="parent">

  1. //span/ancestor::* - returns all ancestors (including parent).

Output: <div class="parent">, <nav class="second_level_ancestor">, <div class="third_level_ancestor">...

  1. //span/ancestor-or-self::* - returns all ancestors and current element itself.

Output: <span>Child</span>, <div class="parent">, <nav class="second_level_ancestor">, <div class="third_level_ancestor">...

  1. //span/ancestor::div[2] - returns second ancestor (starting from parent) of type div.

Output: <div class="third_level_ancestor">

Andersson
  • 51,635
  • 17
  • 77
  • 129
  • Hello @Anderson I need help with my question Do you have time to take a look? Thank you in advance. https://stackoverflow.com/questions/54647055/find-element-by-css-selector?noredirect=1#comment96106980_54647055 –  Feb 13 '19 at 13:35
25

Let's consider your DOM as

<a>
    <!-- some other icons and texts -->
    <span>Close</span>
</a>

Now that you need to select parent tag 'a' based on <span> text, then use

driver.findElement(By.xpath("//a[.//span[text()='Close']]"));

Explanation: Select the node based on its child node's value

Archmede
  • 1,592
  • 2
  • 20
  • 37
Bhuvanesh Mani
  • 1,394
  • 14
  • 23
  • 1
    If we are looking for `div` which is again nested with multiple divs then instead of `.//span` in `By.xpath("//div[.//span[text()='Close']]")` we can use `*//span`, it will look for most parent div element of given span. Now it will look like this `driver.findElement(By.xpath("//div[*//span[text()='Close']]"));` – Jai Prak Jun 20 '18 at 09:25
  • For selenium 4: `driver.find_element(By.XPATH, "//button[.//span[text()='Close']]")` – Ashark Apr 17 '22 at 21:57
  • I prefer your answer due to its simplicity and clarity. I appreciate how you have summed up the solution that seemed to be asked for. I *did* vote up the accepted answer too-because that was helpful for reasons other than the original question. – Pete Kelley Jun 17 '22 at 14:09
15

Take a look at the possible XPath axes, you are probably looking for parent. Depending on how you are finding the first element, you could just adjust the xpath for that.

Alternatively you can try the double-dot syntax, .. which selects the parent of the current node.

drkthng
  • 6,651
  • 7
  • 33
  • 53
prestomanifesto
  • 12,528
  • 5
  • 34
  • 50
6

This might be useful for someone else: Using this sample html

<div class="ParentDiv">
    <label for="label">labelName</label>
    <input type="button" value="elementToSelect">
</div>
<div class="DontSelect">
    <label for="animal">pig</label>
    <input type="button" value="elementToSelect">
</div>

If for example, I want to select an element in the same section (e.g div) as a label, you can use this

//label[contains(., 'labelName')]/parent::*//input[@value='elementToSelect'] 

This just means, look for a label (it could anything like a, h2) called labelName. Navigate to the parent of that label (i.e. div class="ParentDiv"). Search within the descendants of that parent to find any child element with the value of elementToSelect. With this, it will not select the second elementToSelect with DontSelect div as parent.

The trick is that you can reduce search areas for an element by navigating to the parent first and then searching descendant of that parent for the element you need. Other Syntax like following-sibling::h2 can also be used in some cases. This means the sibling following element h2. This will work for elements at the same level, having the same parent.

papigee
  • 6,401
  • 3
  • 29
  • 31
3

We can select the parent tag with the help of Selenium as follows:

driver.findElement(By.xpath("//table[@id='abc']//div/nobr[.='abc']/../.."));

this will help you to find the grandparent of the known Element. Just Remove one (/..) to find the immediate Parent Element.

Like:

driver.findElement(By.xpath("//table[@id='abc']//div/nobr[.='abc']/..));

There are some other ways to implement this, but it worked fine for me.

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
Utsav Jain
  • 31
  • 1
0

You can do this by using /parent::node() in the xpath. Simply append /parent::node() to the child elements xpath.

For example: Let xpath of child element is childElementXpath.

Then xpath of its immediate ancestor would be childElementXpath/parent::node().

Xpath of its next ancestor would be childElementXpath/parent::node()/parent::node()

and so on..

Also, you can navigate to an ancestor of an element using 'childElementXpath/ancestor::*[@attr="attr_value"]'. This would be useful when you have a known child element which is unique but has a parent element which cannot be uniquely identified.

0

Have once way you don't need to execute script and you still get the parent element:

  // identify element
  WebElement ele =driver.findElement(By.xpath("//*[@id=\"ext-gen6\"]/div[5]/"));
  //identify parent element with ./.. expression in xpath
  WebElement parent = ele.findElement(By.xpath("./.."));

The key word here is xpath "./.."

Sang9xpro
  • 435
  • 5
  • 8