2012-10-23 2 views
0

Предположим, что у меня есть таблица HTML со следующими строками,фильтр на основе Дяди в XPath

... 
<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> 
... 

Я хотел бы, чтобы выбрать все <a> элементы в <td> элемент которого связан <th> «s текст находится в небольшом наборе фиксированных заголовков (например, LQM, LBR и RTT). Как я могу сформулировать это как запрос XPath?

EDIT: Я использую Scrapy, набор инструментов для очистки Python, поэтому, если проще рассчитать этот запрос как набор меньших запросов, я был бы более чем счастлив использовать это. Например, если бы я мог выбрать все элементы <tr>, чей первый дочерний элемент <th> соответствует регулярному выражению, затем выберите все <a> потомков оставшихся <tr> элементов, которые были бы великолепными.

ответ

2

Следующая 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:']] 

Я испытал это, добавив <table> тег вокруг входа и применяя следующий 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, то вы можете найти t его конструкция более читаема:

<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> 
+0

Спасибо! Это, безусловно, работает, но это действительно лучший способ? – duckworthd

+0

См. [Этот ответ] (http://stackoverflow.com/a/356777/4525), если вы используете XPath 2.0. В противном случае, да, я думаю, что это лучший способ. – harpo

+0

Также обратите внимание, что я обновил более короткую версию, чем моя первая. – harpo

Смежные вопросы