XPath: Select element by class

Today I was writing some Selenium unit tests for our PHPUnit test suite and needed to check if a certain navigational tab was active. Situation in HTML:

<span class="navbutton active">
  <input type="submit" name="someId" value="Button 1"/>
  <input type="submit" name="someOtherId" value="Button 2"/>
</span>

I needed to check if Button 1 was active. The problem was that with simple xpath constructs like //span[@class='active']/input do not work since the class may have multiple values.

The rescue was the contains function: //span[contains(@class, 'active')]/input[@id='someId'] as parameter to assertElementPresent().

This only does work for simple cases, though: A class like inactive would also match here. The following sections provide real solutions, inspired by Jakob Westhoffs blog entry:

XPath 2.0​

In XPath 2.0, you can split an attribute into tokens and search through them:

//*[count(index-of(tokenize(@class, '\s+' ), '$classname')) = 1]

XPath 1.0​

Many libaries (and thus PHP itself, which utilizes libxml2) only offer XPath 1.0, which means that the tokenize() is not available.

To circumvent that issue, we just search for space + classname + space, and add the spaces around the class attribute so that classes at the beginning and end are caught, too.

//*[contains(concat(' ', normalize-space(@class), ' '), ' $classname ')]

Written by Christian Weiske.

Comments? Please send an e-mail.