2013-02-21 124 views
28

希望有人能帮助我。HtmlAgilityPack和选择节点和子节点

Let's说我有一个包含多个div像这样的例子一个html文件:使用HtmlAgilityPack得到html文件

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

I'm。我需要知道的是,如何获得每个“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都应该是一个对象附带的跨度为属性。 I. e。

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 i'm不是在做它应该做的子节点的搜索。它接触到它一次又一次搜索整个文档。

我的意思是我已经得到它的工作方式,我只是得到整个页面的跨度。但是,我没有跨度和divs之间的关系。意思是:我不知道哪个跨度与哪个div有关。

有人知道解决方案吗?我已经玩了很多,我现在完全混淆:)

任何帮助表示赞赏!

+0

请参阅我对解析代码的方法(完整工作解决方案)的回答。 – 2013-02-22 07:16:58

回答

24

我下面的作品。重要的一点就是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); 
} 
42

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

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

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

或丢弃前缀完全搜索只是直接孩子:

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

如果我这样做:foreach(Node.SelectNodes(“span [@prop]”))中的HtmlAgilityPack.HtmlNode node2 Visual Studio出现错误。 – 2013-02-21 14:00:34

+0

什么样的错误?你也可以尝试使用'。/'前缀。 (我实际上只是猜测) – BeniBela 2013-02-21 14:05:27

+0

我试了两个都结束了:NullReferenceException:对象引用未设置为对象的实例。 – 2013-02-21 14:07:25

2

首先,来看看这个:Html Agility Pack - Problem selecting 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); 
} 
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); 
    } 

上面的代码正在工作。

谢谢你们的时间和帮助!

0

我用过那个。 class convert 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); }