Jeni
Jeni

Reputation: 1118

Selenium WebDriver Xpath current element attribute reports invalid Xpath exception

I have html like

<html>
<body>
  <div class='open'>
    <h1>Title</h1>
    <div>Opened</div>
  </div>
</body>
</html>

And in my Selenium WebDriver 3 tests I am trying to select the div.open element using the following xpath:

//h1/../.[contains(@class, 'open')]

In the following command in c#:

driver.FindElement(By.XPath("//h1/../.[contains(@class, 'open')]"));

Which results in

OpenQA.Selenium.InvalidSelectorException : invalid selector: Unable to locate an element with the xpath expression //h1/../.[contains(@class, 'open')] because of the following error:: Failed to execute 'evaluate' on 'Document': The string '//h1/../.[contains(@class, 'open')]' is not a valid XPath expression.

Searching by the same Xpath in Firefox console successfully locates the element.

Any ideas why WebDriver considers this xpath invalid?

Note: my example is of course simplified

Upvotes: 1

Views: 799

Answers (3)

har07
har07

Reputation: 89325

I would say that's probably down to the specification doesn't explicitly state whether predicate after abbreviated step i.e . and .. should be allowed, neither the specification ever mention an example involving predicate after abbreviated step.

So some XPath implementations just don't support it. One of these, I noticed, is XPath implementation in .NET framework. Other implementations explicitly disallow it, and even provide useful suggestion for the user to replace . or .. in their XPath with the equivalent unabbreviated expression, in order, self::node() or parent::node(), for example, the implementation used by xpathtester. But as you noticed, other implementations might support it.

As of workaround, there are many alternatives XPath which equivalent or close enough to you original attempted XPath. The easiest is to expand the . to its unabbreviated expression, as I mentioned above. Personally, I prefer not to go down the tree and then back up to return a parent element, if possible. Instead, just stop at the parent element which we want to return, and check for the child in predicate :

//*[contains(@class, 'open')][h1]

Upvotes: 3

kb4shubham
kb4shubham

Reputation: 331

If you want to reference "div" with respect to "h1" tag then you can change the xpath to following:

//h1/ancestor::div[contains(@class, 'open')]

Upvotes: 1

undetected Selenium
undetected Selenium

Reputation: 193338

Instead of //h1/../.[contains(@class, 'open')] xpath can you try //div[@class='open'] xpath

Upvotes: 0

Related Questions