5

I have a table like this:

<table>
  <th>
    <td>Area</td><td># of errors</td>
  </th>
  <tr><td>school</td><td>23</td></tr>
  <tr><td>student</td><td>0</td></tr>
  <tr><td>school</td><td>17</td></tr>
  <tr><td>student</td><td>0</td></tr>
</table>

How can I select the last row for the 'Schools' Area.

Until recently I used assert_text with

//table//tr//td[contains(text(),'school')]/following::td

and a value of 0, i.e. zero errors.

However, now I need to account for rows that have errors, but still look at the 'last' row - for an area - that has zero errors.
For this case, using

//table//tr//td[contains(text(),'school')]/following::td

incorrectly selects the first row that has the 23 errors.

I tried using tr[last()] -

//table//tr[last()]//td[contains(text(),'school')]/following::td[2]

but the problem is that this select the last table row - which is for students. I want the last table row that is for schools (it is actually the next to last table row from all rows).

I also tried:

//table//td[contains(text(),'school')][last()]/following::td[2]

but that didn't work (it still selects the 'first' school row).

I need to be able to account for just one school row, two school rows and more than 2 school rows so I need the expression to be dynamic enough to handle that.

0

2 Answers 2

6

You are searching for an element that contains the text 'school', but the markup has the text 'School', XPath is case sensitive.

You can work around this by translating uppercase letters into lower case letters, this would make your XPath like so:

//td[contains(translate(.,'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), 'school')][last()]/following::td[2]

*Note*

I didn't use the XPath2 lower-case() function because it won't work in all browsers.

*Edit*

Updated for the new markup the xpath that is case insensitive would be:

//tr[td[contains(translate(.,'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), 'school')]][last()]/td[2]

or the more simplified version that is not case insensitive would be:

//tr[td[contains(., 'school')]][last()]/td[2]

(. is shorthand for text(), you can interchange them if you want to)

you could probably also get away with

//tr[td[.='school']][last()]/td[2]
Sign up to request clarification or add additional context in comments.

2 Comments

Strange, what you have should work then. Which version of selenium are you using, and which API?
@Ardesco has it basically right. In light of the re-edited example, try this: (//tr[td[.='school')]])[last()]/following::tr/td[2].
2

Using your final XPath, it works for me, and does select the last 'Schools'. So I'd go and ask what versions of everything you are using, what browsers etc

Also, sometimes when using XPath it can be a little fussy with the positional indexers, so what about...

(//td[contains(text(),'School')])[last()]/following::td[2]

2 Comments

I'd be curious whether the problem lies with the IDE or not. Can you run this XPath in Firebug?
look for another addon called firepath. It integrates with firebug and is very useful.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.