Reputation: 180808
I have a bit of HTML that looks like this:
<table class="resultsTable">
<tbody>
<tr class="even">
<td width="35%"><strong>Name</strong></td>
<td>ACME ANVILS, INC</td>
</tr>
</tbody>
</table>
and some C# code that looks like this:
var name = document.DocumentNode
.SelectSingleNode("//*[text()='Name']/following::td").InnerText
which happily returns
ACME ANVILS, INC.
However, there's a new wrinkle. The page in question now returns multiple results:
<table class="resultsTable">
<tbody>
<tr class="even">
<td width="35%"><strong>Name</strong></td>
<td>ACME ANVILS, INC.</td>
</tr>
</tbody>
</table>
<table class="resultsTable">
<tbody>
<tr class="even">
<td width="35%"><strong>Name</strong></td>
<td>ROAD RUNNER RACES, LLC</td>
</tr>
</tbody>
</table>
So now I'm working with
var tables = document.DocumentNode.SelectNodes("//table/tbody");
foreach (var table in tables)
{
var name = table.SelectSingleNode("//*[text()='Name']/following::td").InnerText;
...
}
Which falls over, because SelectSingleNode
returns null.
How do I get my XPath to actually return a result, searching only within the specific table I have selected?
Upvotes: 1
Views: 262
Reputation: 111630
With the addition of a second table, two adjustments are required:
Change your absolute XPath,
//*[text()='Name']/following::td
to one relative to the current table
or tbody
element:
.//*[text()='Name']/following::td
Account for there now being more than one td
element on the
following::
axis.
Either just grab the first,
(.//*[text()='Name']/following::td)[1]
or, better, use the following-sibling::
axis instead in combination
with a test on the string value of td
rather than a test on a text node, which might be buried beneath intervening formatting elements:
.//td[.='Name']/following-sibling::td
See also Difference between Testing text() nodes vs string values in XPath.
Upvotes: 2