带有逻辑AND的'HTML Agility Pack'XPath查询

时间:2012-08-12 19:41:38

标签: c# xpath html-agility-pack

我正在尝试在HTML文档中找到一个表,前两行包含3列文本。

我已尝试使用以下查询,我希望返回表格的前2行包含第一列中的文本的节点:

string xpath = @"//table//table[//tr[1]//td[1]//*[contains(text(), *)] and //tr[2]//td[1]//*[contains(text(), *)]]";
HtmlNode temp = doc.DocumentNode.SelectSingleNode(xpath);

它无法正常工作,mon。

以下是一些示例HTML,这是我要匹配的表格:

    <table width="100%" cellpadding="0" border="0">
       <tbody>
       <tr>
          <td width="27%" valign="center"><b><font size="1" face="Helvetica">SOME TEXT<br></font></b></td>
          <td width="1%"></td>
          <td width="9%" valign="center"><font size="1" face="Helvetica">SOME TEXT<br></font></td>
          <td width="1%"></td>
          <td width="25%" valign="center"><font size="1" face="Helvetica">SOME TEXT<br></font></td>
          <td width="37%"></td>
       </tr>
       <tr>
          <td valign="center"><font size="1" face="Helvetica">SOME TEXT<br></font></td>
          <td></td>
          <td valign="center"><font size="1" face="Helvetica">1<br></font></td>
          <td></td>
          <td valign="center"><font size="1" face="Helvetica">SOME TEXT<br></font></td>
          <td></td>
       </tr>
       </tbody>
</table>

您注意到列1,3,5在前两行中有文本。这就是我想要匹配的东西。

1 个答案:

答案 0 :(得分:1)

//table//table[//tr[1]//td[1]//*[contains(text(), *)] and //tr[2]//td[1]//*[contains(text(), *)]]

此XPath表达式存在许多问题

  1. //table//table选择table后代的任何table。但是,在提供的XML文档中没有嵌套表。

  2. table[//tr[1]//td[1]//*[contains(text(), *)]。谓词中的//tr绝对 Xpath表达式 - 它选择整个文档中的所有tr元素 - 不仅在子树中以此table元素为根。您最有可能想要.//tr而不是//tr

  3. //td[1]选择任何td元素作为其父级的第一个td子元素 - 但最有可能只需要第一个后代td元素。如果是这样,您需要使用此XPath表达式:(//td)[1]

  4. //*[contains(text(), *)]这会选择第一个文本节点子节点包含第一个元素子节点的字符串值的任何元素 - 但您只想验证td是否有后代文本子节点 - 可以使用以下选项正确选择:td[.//text()]

  5. 结合所有这些问题的更正,你可能想要的是

      //table
         [(.//tr)[1]/td[1][.//text()]
        and
          (.//tr)[2]/td[1][.//text()]
         ]
    

    或者,可以编写一个等效但更容易理解且不易出错的表达式,如下所示:

    //table
      [descendant::tr[1]/td[1][descendant::text()]
     and
       descendant::tr[1]/td[1][descendant::text()]
      ]