46

I'm using Html Agility Pack to run xpath queries on a web page. I want to find the rows in a table which contain a certain interesting element. In the example below, I want to fetch the second row.

<table name="important">
<tr>
  <td>Stuff I'm NOT interested in</td>
</tr>
<tr>
  <td>Stuff I'm interested in</td>
  <td><interestingtag/></td>
  <td>More stuff I'm interested in</td>
</tr>
<tr>
  <td>Stuff I'm NOT interested in</td>
</tr>
<tr>
  <td>Stuff I'm NOT interested in</td>
</tr>
</table>

I'm looking to do something like this:

//table[@name='important']/tr[has a descendant named interestingtag]

Except with valid xpath syntax. ;-)

I suppose I could just find the interesting element itself and then work my way up the parent chain from the node that's returned, but it seemed like there ought to be a way to do this in one step and I'm just being dense.

4 Answers 4

79

"has a descendant named interestintag" is spelled .//interestintag in XPath, so the expression you are looking for is:

//table[@name='important']/tr[.//interestingtag]
1
  • very interesting solution Commented Nov 10, 2021 at 11:33
30

Actually, you need to look for a descendant, not a child:

//table[@name='important']/tr[descendant::interestingtag]
7
  • Excellent. That's very helpful. Sorry I can't accept two answers! Commented Jul 7, 2009 at 18:33
  • 2
    I always find it fun how many ways there are to get the desired result in XPath. I believe //table[@name='important']//interestingtag//ancestor::tr should work too I believe.
    – mirod
    Commented Jul 7, 2009 at 18:35
  • @Jeremy Stein: No problem, he beat me to it fair & square. :-) Commented Jul 7, 2009 at 19:12
  • +1 for using the "descendant" axis. More readable than the ".//" shorthand, IMHO.
    – Tomalak
    Commented Jul 8, 2009 at 8:25
  • @Tomalak: you're too kind. :-) I find it more readable as well... too easy to misplace or not see the period, IMHO. Commented Jul 8, 2009 at 18:29
13

I know this isn't what the OP was asking, but if you wanted to find an element that had a descendant with a particular attribute, you could do something like this:

//table[@name='important']/tr[.//*[@attr='value']]
0
3

I know it is a late answer but why not going the other way around. Finding all <interestingtag/> tags and then select the parent <tr> tag.

//interestingtag/ancestor::tr

Not the answer you're looking for? Browse other questions tagged or ask your own question.