3

I have CSS selector and was trying to apply it in selenium. Css selector is .parentclass:not(:has(.childclass)). I am trying to get all parent elements which do not have descendent element with class childclass. It works perfect in jQuery. But in selenium seems it doesn't work.

So I decided to try XPath. What is the equivalent in XPath to the aforementioned CSS selector? I was able to get worked the following: //*[contains(@class, 'parentclass')]. But this is only first part of the condition. How can I say in XPath that I need only parents which don't contain children with CSS class childclass?

kjhughes
  • 106,133
  • 27
  • 181
  • 240
Andrei Tarutin
  • 684
  • 1
  • 10
  • 25

1 Answers1

4

This XPath,

//*[contains(@class, 'parentclass') and not(*[contains(@class, 'childclass')])]

will select all elements whose @class attribute contains "parentclass" and whose children do not have a @class attribute containing "childclass".

Apply the space-padding trick to avoid false substring matches if necessary.


Update per OP comment:

The above XPath can easily be adapted to exclude those elements whose descendants, rather than children, meet the stated condition:

//*[contains(@class, 'parentclass') and not(.//*[contains(@class, 'childclass')])]
Community
  • 1
  • 1
kjhughes
  • 106,133
  • 27
  • 181
  • 240
  • Unfortunately, the suggested solution doesn't work. It still returns all the parents. Here is my XPath: `//li[contains(@class, 's-result-item') and not(*[contains(@class, 's-sponsored-list-header')])]`. This query returns all `li` with class `s-result-item` even those with child element with class `s-sponsored-list-header` inside. But I need only those parents, which doesn't contain any child element with class `s-sponsored-list-header`. – Andrei Tarutin Mar 26 '17 at 14:58
  • By the way, child element doesn't mean first-level child. It can be on any level inside parent. Maybe, this is the reason why I am getting all the parents? – Andrei Tarutin Mar 26 '17 at 15:00
  • I found following XPath works fine: `//li[contains(@class, 's-result-item') and not(.//*[contains(@class, 's-sponsored-list-header')])]`. The difference is only in second condition I believe in this case I am trying to find the child element on any level inside parent. Am I right? Is it correct query? – Andrei Tarutin Mar 26 '17 at 15:17
  • You're using the word 'child` wrong, then. The word you seem to want instead would be 'descendant'. Per your next comment, yes, you want `.//*` rather than `*` if you want descendants, not just children. Answer updated. – kjhughes Mar 26 '17 at 17:36
  • Yes, you are right, I needed descendants rather than children. Thank you for helping. – Andrei Tarutin Mar 26 '17 at 18:04