2014-08-27 22 views
1

我正在使用HtmlAgilityPack抓取一些數據。HtmlAgilityPack NextSibling.InnerText值爲空

的HTML看起來像這樣:

<div id="id-here"> 
    <dl> 
    <dt> Field Name </dt> 
    <dd> Value for above field name </dd> 
    <dt> Field Name </dt> 
    <dd> Value for above field name </dd> 
    <dt> Field Name </dt> 
    <dd> Value for above field name </dd> 
    </dl> 
</div> 

現在我的問題是,沒有永遠場的一組數字,所以我不能可靠地訪問他們每個人都喜歡:

//*[@id="id-here"]/dl[1]/dd[1] 

因爲dd [1]可能是一個頁面上的名稱,另一個是另一個電話,因爲用戶未填寫名稱,因此字段被隱藏。

所以我搶,像這樣所有的DT和DD節點:

//*[@id="id-here"]/dl[1]/dt | //*[@id="id-here"]/dl[1]/dd 

現在我檢查每個節點,看它是否符合現場我想,走NextSibling值,像這樣:

foreach (HtmlNode node in details) 
    { 
     if (node.InnerText.Contains("Tel:")) telephone = node.NextSibling.InnerText; 
     if (node.InnerText.Contains("Email:")) email = node.NextSibling.InnerText; 
    } 

這適用於電話,但由於某些原因,當「電子郵件:」節點出現時,兩個NextSibling.InnerHTML & NextSibling.InnerText都是空白的,儘管下一個兄弟姐妹確實擁有數據。如果我真的去nodedetails並看看它InnerHTML是整個格式化的鏈接和InnerText是電子郵件地址。

NextSibling.InnerText不工作,因爲A標籤使它成爲一個孩子或什麼東西?我看了一下調試器,只是在NextSibling找不到我需要的信息。

我確定答案是可笑的簡單,我只是無法弄清楚。有人把我從痛苦中解救出來了嗎?

+0

有點單獨的問題,但爲什麼你選擇'dd'元素,如果你實際上並沒有計劃在迭代'details'時使用所選的'dd'? – JLRishe 2014-08-27 19:28:55

+0

這樣我可以選擇下一個兄弟。如果我不選擇DD,那麼他們不會在那裏成爲下一個兄弟。 – Guerrilla 2014-08-27 19:33:54

+0

「細節」的內容與節點的兄弟姐妹的內容沒有關係,這正是您在這裏目睹的內容。 – JLRishe 2014-08-27 19:37:50

回答

8

發生這種情況的原因是,如果node是從它的對應的dd元件由一些空白分開的dt元件,然後node.NextSibling是一個全功能的空白文本節點(</dt><dd>之間的空間)。如果你在調試器中看它,你會看到node.NextSiblingNodeTypeHtmlNodeType.Text而不是HtmlNodeType.Element

我建議創建一個方便的方法來獲得的dt節點的相應dd文:

internal static string GetMatchingDdValue(HtmlNode dtNode) 
{ 
    var found = dtNode.SelectSingleNode("following-sibling::*[1][self::dd]"); 
    return found == null ? "" : found.InnerText; 
} 

然後你可以使用它像這樣:

if (node.InnerText.Contains("Tel:")) { telephone = GetMatchingDdValue(node); } 

這裏的細目在我的方法中使用的有點棘手的XPath:

(a) following-sibling::* 

^選擇與父節點共享同一個 作爲當前節點並在其後發生的所有元素。

(b) following-sibling::*[1] 

^選擇集合中的第一節點(A) (如果有的話)

(c) following-sibling::*[1][self::dd] 

^選擇組中的所有節點(b)該 是與名稱 「DD」 的元件

SelectSingleNode()選擇集合(c)中的第一個節點,它應始終爲1或0個節點。

您可能很有可能只與following-sibling::ddfollowing-sibling::*,但上述路徑包含保護措施。例如,如果由於某種原因,你有以下的XML和當前節點是Tel:元素:

<dl> 
    <dt>Tel:</dt> 
    <dt>Address:</dt> 
    <dd>50 Fake St.</dd> 
</dl> 

following-sibling::dd會給你的結果「50假聖」,而following-sibling::*會給你的結果「地址:」。相反,在這種情況下,following-sibling::*[1][self::dd]會選擇一個空的節點集,所以該方法會正確地產生一個空字符串作爲結果。

+0

嘎,打我5秒:)(和代碼!) – paul 2014-08-27 19:37:52

+0

謝謝,它完美的作品。讓我困惑的是,當我在調試器中打開'details'並且看到「Email:」在[0]處,然後電子郵件地址在[1]時,所以我認爲NextSibling會得到下一個條目。 我是xpath的新手,完全不瞭解你的xpath是如何工作的,我試圖從工作中引用,但沒有完全理解它。我想我需要寫一本書。 – Guerrilla 2014-08-27 20:11:28

+0

following-siblings =在此節點後取所有html * =取任何html。 [1] = ?? [self :: dd] =選擇當前節點並選擇dd?代碼仍然有效,如果我刪除這個位 – Guerrilla 2014-08-27 20:21:42