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.