[英]HtmlAgilityPack and selecting Nodes and Subnodes
希望有人可以幫助我。
假設我有一個包含多個divs
的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>
我正在使用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
和divs
之間沒有關系。 意思是,我不再知道哪個span
與哪個div
相關。
有人知道解決方案嗎? 我已經玩了那么多,我現在完全糊塗了。 :)
任何幫助表示贊賞!
如果您使用//
,它將從文檔開始搜索。
使用.//
從當前節點搜索所有
foreach (HtmlAgilityPack.HtmlNode node2 in node.SelectNodes(".//span[@prop]"))
或者完全刪除前綴以僅搜索直接子項:
foreach (HtmlAgilityPack.HtmlNode node2 in node.SelectNodes("span[@prop]"))
以下對我有用。 重要的一點正如 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);
}
首先看看這個: 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);
}
為我感到羞恥:)
你們都是對的。
我發現了問題。 這個 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);
}
上面的代碼正在工作。
謝謝你們的時間和幫助!
我用過那個。 類轉換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); }
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.