While looking for a way to select a CSS class with XPath in a reliable way. I came across many solutions, and while they felt obvious, they were flawed as well. So lets start with the most reliable way I found so far.
How do you do this in XPath?
XPath doesn’t have a native equivalent of a CSS class selector. Where .className will select any element that has the class className. The closest equivalent is:
//*[contains(concat(" ", normalize-space(@class), " "), " className ")]
The function normalize-space strips leading and trailing whitespace and also replaces sequences of whitespace characters by a single space.
Similiarly it is equivalent to the CSS selector:
*[class~="className"]
which will match any element whose class attribute value is a list of whitespace-separated values, one of which is exactly equal to className.
The obvious but wrong ways to do it
The XPath selector:
//*[@class="className"]
doesn’t work because it won’t match an element that has more than one class, for example
<div class="className anotherClassName">
It also won’t match if there is any extra whitespace around the class name:
<div class=" className ">
The ‘improved’ XPath selector:
//*[contains(@class, "className")]
doesn’t work either because it wrongly matches elements with the class classNameTwo, for example:
<div class="classNameTwo">