2012-07-30 116 views
0

我使用HtmlAgilityPack來解析和分析HTML頁面,我需要知道每個節點的「深度」 - 距離Body節點的距離。示例(「深度」屬性僅用於說明目的):如何獲取HTML樹中的節點深度?

<html> 
    <head></head> 
    <body depth="0"> 
    <div depth="1"> 
     <ul depth="2"> 
     <li depth="3"> 
      <p depth="4">foo</p> 
     </li> 
     <li depth="3"> 
      <p depth="4">bar</p> 
     </li> 
     </ul> 
    </div> 
    </body> 
</html> 

我試圖避免兩個明顯的解決方案:

  • 掃描HTML樹(DFS,BFS等。 ),計算每個節點的深度,並將這些值存儲在字典或類似內容中。
  • 通過計算node.ParentNode來計算每個節點「按需」的深度,直到達到body

有沒有辦法通過以某種方式使用HtmlAgilityPack在Load上收集的已有數據來避免這些問題?

回答

1

你問是否有內置的NodeDepth屬性或類似的東西?我很確定答案是否定的,因爲計算出由庫解析的每個節點都會產生很少被保證的開銷。由於計數節點深度很容易用一些遞歸來完成,我不認爲他們會在默認情況下包含它。

爲什麼你想避免顯而易見的解決方案?

+0

正如你自己所指出的那樣,它會產生開銷。遞歸很容易編寫,但在我的情況下很難表現(我已經對其進行了描述)。 我知道沒有'NodeDepth'屬性,但仍然在尋找別的東西可以幫助... – seldary 2012-07-30 07:45:05

+0

啊,你的希望是解析器保持這個計數在可用的地方,所以你不必再次導航樹解析完成後?有道理,但我傾向於說,除非你改變圖書館本身,否則這是不可能的......這可能是一個可行的解決方案,這取決於它的重要性。 – 2012-07-30 07:51:16

3

據我所知,AgilityPack不存儲節點的深度。

如果你想獲得深度所有節點,假設,它會更容易例如寫遞歸方法從根節點開始,並且遞增調用深度,遞歸調用當前節點的子節點。

至於單個節點的深度計算,您可以使用HtmlNode.XPath屬性,並計算此值中的斜線數(/)。這將是節點深度。在你的情況,你應該首先計算<body>節點的深度,然後。減去從願望節點的深度此值,以獲得相對深度

var bodyDepth = doc.DocumentNode 
    .SelectSingleNode("//body") 
    .XPath 
    .Count(c => c == '/'); 
var paragraphDepth = doc.DocumentNode 
    .SelectSingleNode("//p") 
    .XPath 
    .Count(c => c == '/'); 
var result = paragraphDepth - bodyDepth; 

這會給你4,但我不知道這比遍歷ParentNode屬性更容易。

+0

如何在純js中做到這一點? – SuperUberDuper 2015-03-30 13:53:11

0

HtmlAgilityPack不會給出深度細節。我們可以使用上面提供的'/'字符計數從XPath變量中獲取它。我們不需要通過父母來獲取詳細信息。

foreach (HtmlNode rootNode in document.DocumentNode.Descendants()) 
      { 
       levels.Add(rootNode.XPath.Count(x => x == '/')); 
      } 

它應該工作。