Reputation: 58
I have the following I am trying to analyse using xpath
<table>
<tr>
<td>Name</td>
<td>Info</td>
<td><a href = "file1">Download</a></td>
</tr>
<tr>
<td>Name2</td>
<td>Info</td>
<td><a href = "file2">Download</a></td>
</tr>
....
<tr>
..
</tr>
</table>
I have the following xpath to grab the download links
$xpath->query("//a[text()='Download']/@href");
What I am trying to figure out is the query to send to grab the Name of each of the downloads.
The page has no div id markups at all, just plain table, tr, td tags.
I have tried something like
$xpath->query("//preceding-sibling::a[text()='Download']");
Does anyone have any idea on this?
Upvotes: 0
Views: 1975
Reputation: 25034
Close!
Given a particular context node (here, the href
attribute for a download), you want to find the eldest sibling of the td
containing the context node. So your relative path should first ascend to the td
and then find the oldest sibling:
parent::a/parent::td/preceding-sibling::td[last()]
or more briefly (and without assuming that there are no elements like p
or span
intervening between the td
and the a
):
ancestor::td[1]/preceding-sibling::td[last()]
Some users find the reverse numbering of nodes on the preceding-sibling
axis confusing, so it may feel simpler to say that what you really want is the first td
child of the smallest containing tr
:
ancestor::tr[1]/child::td[1]
If you need in a single pass to pick up all the download links and the textual label for them, then how you do it depends on the context in which you're using XPath. In XSLT, for example, you might write:
<xsl:apply-templates select="//a[text()='Download']/@href"/>
and then fetch the label in the appropriate template:
<xsl:template match="a/@href">
<xsl:value-of select="string(ancestor::tr[1]/td[1])"/>
:
<xsl:value-of select="."/>
</xsl:template>
In other host languages, you will want to do something similar. The key problem is that you have to iterate over the nodes matching your expression for href
, and then for each of those nodes you need to move back in the document to pick up the label. How you say "evaluate this second XPath expression based on the current node from the first XPath expression" will vary with your environment.
Upvotes: 1