When using Selenium, whether it’s for load testing, website monitoring, or just for basic functional testing, you will eventually find the need to work with lists of elements. When this need arises, you will probably find that the getXpathCount function is really helpful.
As you might expect, get getXpathCount returns a number that is the count of elements matching the supplied xpath expression. For example, suppose your DOM/HTML looked like this:
- html
- head
- title
- body
- table
- tbody
- tr
- td
- tr
- td
- td
- td
- checkbox
- tr
- td
- tr
- td
- td
- td
- checkbox
- tr
- td
- tr
- td
- td
- td
- checkbox
This DOM structure is basically showcasing a table with 6 rows, where every other row contains a button in the third column. You could the count of all the buttons on the page with a very simple call:
var count = selenium.getXpathCount("//checkbox");
Now suppose you wanted to click on all the checkboxes. You might be inclined to write this code:
var count = selenium.getXpathCount("//checkbox"); for (var i = 1; i <= count; i++) { selenium.click("//checkbox[" + i + "]"); }
While this seems intuitive, it’s actually incorrect and is a very common mistake, even for advanced Selenium users. The core reason is that it misunderstands the core syntax of xpath. Let me explain…
When you write an xpath expression like //checkbox, you’re really saying: find all ancestors of the document that are checkbox elements. Similarly, when your expression is //checkbox[contains(@id, 'foo')] you’re asking for all checkbox elements that match expression contains(@id, ‘foo’), which is basically checking for checkboxes with an ID that has the text “foo” in it.
Where people often get tripped up is in understanding what //checkbox[2] means. It does not mean that it should return the second checkbox on the page, which you might think at first. Instead, it means find all checkboxes that happen to be the second checkbox relative to their parent.
That means that in our example //checkbox[1] would actually return all three checkboxes, but checkbox[2] and checkbox[3] would return nothing, because there are no checkboxes that happen to be the 2nd or 3rd checkbox relative to their parent. But because clicking on //checkbox[1] in Selenium will only click on the first one, the code snippet won’t do what you thought it would.
So what’s the solution? You have to use the xpath count to create an expression that maps to each unique checkbox:
var count = selenium.getXpathCount("//checkbox"); for (var i = 1; i <= count; i++) { selenium.click("//tr[" + (count * 2) + "]//checkbox"); }
What this does is recognize that there are two rows for every one checkbox, and that the rows with the checkbox are 2, 4, 6, etc. Depending on how the HTML is constructured, you may need a more complex xpath expression, but the basic principal still applies: use the count to uniquely map to each element. And when in doubt, use Firebug to easily test those xpath expressions.
Update: Marc Guillemot, of HtmlUnit fame, commented that there is a way to simply get the second or third checkbox by simply doing (//checkbox)[2] and (//checkbox)[3]. He’s absolutely right and we should have pointed that out from the beginning!
Our point of this post was to try to highlight the common mistake many Selenium users make when trying to do things like this and explain what example //checkbox[2] really means, but we should have explained that you can indeed get the Nth result from an xpath expression by wrapping it with parens. Thanks for the tip, Marc!




and what about “(//checkbox)[2]“, “(//checkbox)[3]“, …?
Of course, in Selenium, that’s “xpath=(//checkbox)[2]“, because “(//…” won’t trigger the auto-detection of XPath locators like “//…” does.
Nice Explanation
Very nice explanation.
I hope ‘dom’ locators also useful in this case.
Say for example,to point the 2nd anchor in page
dom=document.getElementsByTagName(‘a’)[1]
Hi,
Does this work on IE7?? I tried using the same logic in IE7 but was getting an error. Please help.
ERROR: Invalid xpath [3]: XPath parse error //DIV[//INPUT id=check]:
//
Step
[
Expr
Expr
]
@Abhilash
This doesn’t work in IE because of the adressing of xpath in IE. In all browsers the number of elements start with 1 where in IE it starts with 0.
For the example above: changing your xpath number to (count -1) for IE would do the trick.
Hi Friends,
How to count a xpath using xpath?? In above messages we are counting the xpaths for check box.
But my case, i have xpath’s, where i have to count all the similar xpath’s.
Hi, Can you please give the download link for selenium.pm file that contains the getxpathcount function..