XPath中基于叔叔的过滤器
假设我有一个包含以下行的HTML表XPath中基于叔叔的过滤器,xpath,scrapy,Xpath,Scrapy,假设我有一个包含以下行的HTML表 ... <tr> <th title="Library of Quintessential Memes">LQM:</th> <td> <a href="docs/lqm.html"><b>Intro</b></a> <a href="P/P79/">79</a> <a href="P/P80/">
...
<tr>
<th title="Library of Quintessential Memes">LQM:</th>
<td>
<a href="docs/lqm.html"><b>Intro</b></a>
<a href="P/P79/">79</a>
<a href="P/P80/">80</a>
<a href="P/P81/">81</a>
<a href="P/P82/">82</a>
</td>
</tr>
<tr>
<th title="Library of Boring Books">LBB:</th>
<td>
<a href="docs/lbb.html"><b>Intro</b></a>
<a href="R/R80/">80</a>
<a href="R/R81/">81</a>
<a href="R/R82/">82</a>
<a href="R/R83/">83</a>
<a href="R/R84/">84</a>
</td>
</tr>
...
。。。
LQM:
LBB:
...
我想选择
元素中的所有
元素,其关联的
文本位于一小组固定标题中(例如LQM、LBR和RTT)。如何将其表述为XPath查询
编辑:我使用的是Scrapy,一个Python刮片工具包,因此如果将这个查询作为一组较小的查询来表达更容易,我将非常乐意使用它。例如,如果我可以选择第一个
子元素与正则表达式匹配的所有
元素,然后选择剩余
元素的所有
子元素,那就太棒了。以下XPath可以工作:
//a[contains(',LQM:,LBR:,RTT:,',
concat(',', ancestor::td/preceding-sibling::th, ','))]
理论上,这可能会得到一些误报(如果代码中包含逗号)
更严格的说法是:
//a[ancestor::td/preceding-sibling::th[.='LQM:']]
|//a[ancestor::td/preceding-sibling::th[.='LBR:']]
|//a[ancestor::td/preceding-sibling::th[.='RTT:']]
我通过在输入周围添加
标记并应用以下XSL转换来测试这一点:
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="//a[ancestor::td/preceding-sibling::th[.='LQM:']]
|//a[ancestor::td/preceding-sibling::th[.='LBR:']]
|//a[ancestor::td/preceding-sibling::th[.='RTT:']]">
<xsl:text>
</xsl:text>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:transform>
它产生以下输出:
<a href="docs/lqm.html"><b>Intro</b></a>
<a href="P/P79/">79</a>
<a href="P/P80/">80</a>
<a href="P/P81/">81</a>
<a href="P/P82/">82</a>
当然,如果您使用的是XSL,那么您可能会发现这种结构更具可读性:
<xsl:for-each select="//a">
<xsl:variable name="header" select="ancestor::td/preceding-sibling::th"/>
<xsl:if test="$header='LQM:' or $header = 'LBR:' or $header = 'RTT:'">
<xsl:text>
</xsl:text>
<xsl:copy-of select="."/>
</xsl:if>
</xsl:for-each>
以下XPath将起作用:
//a[contains(',LQM:,LBR:,RTT:,',
concat(',', ancestor::td/preceding-sibling::th, ','))]
理论上,这可能会得到一些误报(如果代码中包含逗号)
更严格的说法是:
//a[ancestor::td/preceding-sibling::th[.='LQM:']]
|//a[ancestor::td/preceding-sibling::th[.='LBR:']]
|//a[ancestor::td/preceding-sibling::th[.='RTT:']]
我通过在输入周围添加
标记并应用以下XSL转换来测试这一点:
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="//a[ancestor::td/preceding-sibling::th[.='LQM:']]
|//a[ancestor::td/preceding-sibling::th[.='LBR:']]
|//a[ancestor::td/preceding-sibling::th[.='RTT:']]">
<xsl:text>
</xsl:text>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:transform>
它产生以下输出:
<a href="docs/lqm.html"><b>Intro</b></a>
<a href="P/P79/">79</a>
<a href="P/P80/">80</a>
<a href="P/P81/">81</a>
<a href="P/P82/">82</a>
当然,如果您使用的是XSL,那么您可能会发现这种结构更具可读性:
<xsl:for-each select="//a">
<xsl:variable name="header" select="ancestor::td/preceding-sibling::th"/>
<xsl:if test="$header='LQM:' or $header = 'LBR:' or $header = 'RTT:'">
<xsl:text>
</xsl:text>
<xsl:copy-of select="."/>
</xsl:if>
</xsl:for-each>
谢谢!这当然有效,但这真的是最好的方法吗?看看您是否在使用XPath2.0。否则,是的,我认为这是最好的方法。还要注意,我更新了一个比我的第一个版本更短的版本。谢谢!这当然有效,但这真的是最好的方法吗?看看您是否在使用XPath2.0。另外,是的,我认为这是最好的方法。还要注意的是,我更新了一个比第一个版本更短的版本。