使用HTML Agility Pack和Linq解析html

c# html-agility-pack html-parsing linq

我有以下HTML

(..)
<tbody>
 <tr>
  <td class="name"> Test1 </td>
  <td class="data"> Data </td>
  <td class="data2"> Data 2 </td>
 </tr>
 <tr>
  <td class="name"> Test2 </td>
  <td class="data"> Data2 </td>
  <td class="data2"> Data 2 </td>
 </tr>
</tbody>
(..)

我的信息是name => so“Test1”和“Test2”。我想知道的是如何根据我的名字获取“data”和“data2”中的数据。

目前我正在使用:

var data =
    from
        tr in doc.DocumentNode.Descendants("tr")
    from   
        td in tr.ChildNodes.Where(x => x.Attributes["class"].Value == "name")
    where
        td.InnerText == "Test1"
    select tr;

但是当我尝试查看data时,我得到{"Object reference not set to an instance of an object."}

一般承认的答案

至于您的尝试,您的代码有两个问题:

  1. ChildNodes很奇怪 - 它还返回空白文本节点,它们没有class属性(当然不能有属性)。
  2. 正如詹姆斯沃尔福德评论的那样,文本周围的空间很重要,你可能想要修剪它们。

通过这两个更正,以下工作:

var data =
      from tr in doc.DocumentNode.Descendants("tr")
      from td in tr.Descendants("td").Where(x => x.Attributes["class"].Value == "name")
     where td.InnerText.Trim() == "Test1"
    select tr;

热门答案

这是XPATH方式 - 嗯......每个人似乎都忘记了XPATH的强大功能,专注于C#XLinq,这些天:-)

此函数获取与名称关联的所有数据值:

public static IEnumerable<string> GetData(HtmlDocument document, string name)
{
    return from HtmlNode node in
        document.DocumentNode.SelectNodes("//td[@class='name' and contains(text(), '" + name + "')]/following-sibling::td")
        select node.InnerText.Trim();
}

例如,此代码将转储所有“Test2”数据:

    HtmlDocument doc = new HtmlDocument();
    doc.Load(yourHtml);

    foreach (string data in GetData(doc, "Test2"))
    {
        Console.WriteLine(data);
    }


许可下: CC-BY-SA with attribution
不隶属于 Stack Overflow
这个KB合法吗? 是的,了解原因
许可下: CC-BY-SA with attribution
不隶属于 Stack Overflow
这个KB合法吗? 是的,了解原因