48

希望有人能帮助我。

假设我有一个html包含多个divs这样的示例的文档:

<div class="search_hit">
    <span prop="name">Richard Winchester</span>
    <span prop="company">Kodak</span>
    <span prop="street">Arlington Road 1</span>
</div>
<div class="search_hit">
    <span prop="name">Ted Mosby</span>
    <span prop="company">HP</span>
    <span prop="street">Arlington Road 2</span>
</div>

HtmlAgilityPack用来获取html文件。我需要知道的是如何获得每个跨度search_hit-div

我的第一个想法是这样的:

foreach (HtmlAgilityPack.HtmlNode node in
    doc.DocumentNode.SelectNodes("//div[@class='search_hit']"))
{
     foreach (HtmlAgilityPack.HtmlNode node2 in node.SelectNodes("//span[@prop]"))
     {
     }
}

每个都div应该是一个包含跨度作为属性的对象:

public class Record
{
    public string Name { get; set; }
    public string company { get; set; }
    public string street { get; set; }
}

然后应填写此列表:

public List<Record> Results = new List<Record>();

但是XPATH我正在使用的不是应该在子节点中进行搜索。它似乎一次又一次地搜索整个文档。

spans我的意思是我已经以这种方式工作了,我只是获得了整个页面的跨度,但是我与and之间没有关系divs。意思是,我不再知道哪个span与哪个有关div

有人知道解决方案吗?我已经玩了那么多,现在我完全糊涂了。:)

任何帮助表示赞赏!

4

5 回答 5

62

如果使用//,它会从文档开始搜索。

用于.//从当前节点搜索所有

 foreach (HtmlAgilityPack.HtmlNode node2 in node.SelectNodes(".//span[@prop]"))

或完全删除前缀以仅搜索直接子级:

 foreach (HtmlAgilityPack.HtmlNode node2 in node.SelectNodes("span[@prop]"))
于 2013-02-21T13:55:06.840 回答
39

以下对我有用。正如 BeniBela 指出的那样,重要的一点是在第二次调用“SelectNodes”时添加一个点。

List<Record> lstRecords=new List<Record>();
foreach (HtmlNode node in doc.DocumentNode.SelectNodes("//div[@class='search_hit']"))
{
  Record record=new Record();
  foreach (HtmlNode node2 in node.SelectNodes(".//span[@prop]"))
  {
    string attributeValue = node2.GetAttributeValue("prop", "");
    if (attributeValue == "name")
    {
      record.Name = node2.InnerText;
    }
    else if (attributeValue == "company")
    {
      record.company = node2.InnerText;
    }
    else if (attributeValue == "street")
    {
      record.street = node2.InnerText;
    }
  }
  lstRecords.Add(record);
}
于 2013-02-21T23:06:38.527 回答
3

首先看一下这个:Html Agility Pack - Problem selection subnode

这是您问题的完整解决方案:

IList<Record> results = new List<Record>();
foreach (var node in doc.DocumentNode.SelectNodes("//div[@class='search_hit']")) {
    var record = new Record();
    record.Name = node.SelectSingleNode(".//span[@prop='name']").InnerText;
    record.company = node.SelectSingleNode(".//span[@prop='company']").InnerText;
    record.street = node.SelectSingleNode(".//span[@prop='street']").InnerText;
    results.Add(record);
}

如果您阅读了我指出的问题,您会发现做的事情./span[@prop='name']是完全相同的,因为这些span节点是节点的(直接)子div节点。


如果span节点没有这些prop属性,并且您想根据它们出现的顺序分配它们,您可以执行以下操作:

foreach (var node in doc.DocumentNode.SelectNodes("//div[@class='search_hit']")) {
    var spanNodes = node.SelectNodes("./span");
    var record = new Record();
    record.Name = spanNodes[0].InnerText;
    record.company = spanNodes[1].InnerText;
    record.street = spanNodes[2].InnerText;
    results.Add(record);
}
于 2013-02-22T07:16:33.367 回答
2

为我感到羞耻:)

你们都是对的。

我发现了问题。这个 NullReferenceException 一直困扰着我,所以我花了更多时间详细查看它。在所有这些 div 之间,有一个 div 具有相同的“class='search-hit'”属性,但内部没有跨度。这就是它在第二个循环中出现错误的原因。

foreach (HtmlAgilityPack.HtmlNode node in doc.DocumentNode.SelectNodes("//span[@prop]/ancestor::div[@class='search_hit']"))
   {
        Record rec = new Record();
        foreach (HtmlAgilityPack.HtmlNode node2 in node.SelectNodes(".//span[@prop]"))
           {
           }
           rList.Results.Add(rec);
   }

上面的代码正在运行。

谢谢你们的时间和帮助!

于 2013-02-22T12:47:08.547 回答
0

我用那个。类转换id

  HtmlNodeCollection nodes = dokuman.DocumentNode.SelectNodes("//div[@id='search_hit']//span[@prop]");


            for (int i = 0; i < nodes .Count; i++)
        {
            var record = new Record();


                record.Name = links[i].InnerText;   results.Add(record);  }
于 2016-06-14T07:27:27.707 回答