5

There were already some discussion about the Nth element in XPath:

XPath query to get nth instance of an element

Get Nth child of a node using xpath

XPath and PHP: Parse from the nth instance of an element

I'm using Selenium and PHPUnit for funcional testing. My problem is that on a page with a large form the Nth selector is not working. I have 80 input fields (using Selenium's getXpathCount('//input') call to get the exact number) - and I would like to iterate through that 80 fields and type some text. What I've already tried and not working (N is the index variable):

//input[N]
//input[position()=N]
input[N]
(//input)[N]
(.//input)[N]
css=input:nth-of-type(N)

And all the mixtures of the ones above. It usually fires an Exception saying: element not found at N = 2. I tried several XPath tools for browsers, so as native extensions like XPathEvaluator in Chrome - almost all gave me proper results. So it seems Seleniums XPath parser works a bit different way.

What do you think? Do I miss a major thing?

Update: Here you are my solution: getAllFields(): http://release.seleniumhq.org/selenium-remote-control/0.9.0/doc/java/com/thoughtworks/selenium/DefaultSelenium.html#getAllFields() and then I iterate through.

It actually doesn't solve the original problem, so I'm still interested about the answer.

Thanks!

Community
  • 1
  • 1
itarato
  • 795
  • 1
  • 8
  • 24
  • I'm pretty sure Selenium does not provide full, standard XPath. But I can't put my finger on the evidence right now, other than what you've just posted. Your expression `(//input)[N]` should work. – LarsH Oct 07 '11 at 05:12
  • @LarsH: There may be parts of XPath 1.0 that the Selenium RC API doesn't support correctly, but I'm not aware of any. I've certainly used the XPath version of these sorts of things many times, and they work just fine. – Ross Patterson Oct 07 '11 at 22:56
  • @Ross: good to know. I'll keep my eye out for exceptions in the future, since I don't have any specifics to offer. – LarsH Oct 08 '11 at 03:16

4 Answers4

11

(//input)[15] returns the 15th input element in the document

//input[15] returns every input element that is the 15th input child of its parent element.

So some of your expressions at least are incorrect. But they aren't all incorrect, so I don't know why it isn't working for you.

Michael Kay
  • 156,231
  • 11
  • 92
  • 164
  • @itarato, Michael means in standard XPath (not necessarily in Selenium XPath). – LarsH Oct 07 '11 at 05:10
  • Sure, I'm also aware of that. I was just bluffing all around. – itarato Oct 07 '11 at 18:55
  • @LarsH: It means the same thing in Selenium. – Ross Patterson Oct 07 '11 at 22:54
  • OMG. Never realised you had to/could wrap xpath result in brackets to get the nth element. Was scratching my head thinking why is the second variant not working! (was using in conjunction with attribute selection of the kind `//div[@class='blah']`. Without it I was getting multiple – JGFMK May 04 '22 at 07:19
3

Without seeing your specific code and HTML, we're mostly guessing here. But xpath=(//input)[2] will find the second input field on the page, regardless of where it is. Be sure to include the xpath=, because Selenium RC doesn't assume it unless the locator starts with //. Note also that in XPath, n starts at 1, not at 0 like in C-derived languages.

Ross Patterson
  • 9,527
  • 33
  • 48
2

This one worked for me:

/descendant::input[@id="search_query"][2]

See also this answer

Community
  • 1
  • 1
madpoet
  • 1,023
  • 11
  • 28
-1

I don't use PHPUnit but I love XPath.

In search field of Safari's inspector:

//input[N]

or scoped:

//div/input[N]    means second input in a div
(//div/input)[N]  means second div that has an input (select the first input)
yitsushi
  • 1,173
  • 7
  • 6
  • What I get is: //input[1] = all inputs //input[2] = empty In my case there is no common parent of input fields. – itarato Oct 06 '11 at 11:11
  • That's because `//input[1]` means "Anywhere in the document (`//`), any input element (`input`) that is the first child of its parent element (`[1]`)". Contrary to what most C-trained programmers expect, `[1]` does not mean "first input element of the set", instead it's an abbreviation for `position() = 1`. It works for `(//input)[1]` because `(//input)` is the set of all input elements, and the `position()` applies to the set. Whereas in `//input[1]`, the `position()` applies to the element. – Ross Patterson Oct 09 '11 at 13:34
  • I was able to leverage this solution: (.//*[@id='myID']/tbody/tr[2]/td[4]/a)[1] where [4] is the column number and [1] is the row number. – Rick Johnson Nov 09 '16 at 20:24