2012-03-16 49 views
1

我使用HTMLAgility包做HTML輸出一些對即時修改 - 查找所有文本節點並替換它們:HTMLAgility包:在「混合型」更換內容節點

const string xpath = "//*[not(self::script or self::style)]/text()[normalize-space(.) != '']"; 
var docNodes = doc.DocumentNode.SelectNodes(xpath).ToList(); 
foreach (var htmlNode in nodes) 
{ 
    var parent = htmlNode.ParentNode; 
    var newNode = new HtmlNode(HtmlNodeType.Text, doc, 0){InnerHTML = "Test"}; 
    parent.ReplaceChild(newNode, htmlNode); 
}     

但是,如果textnode不是父級的唯一孩子,這似乎會導致問題。例如:

<label>Email:<br><input name="txtID" type="text" id="txtID" class="input"></label> 

被置換後,訪問doc.DocumentNode.OuterHTML導致以下例外: 無法轉換類型「HtmlAgilityPack.HtmlNode」的目的爲類型「HtmlAgilityPack.HtmlTextNode」。

我正在更換不正確嗎?我不能真正去「清理」可能貫穿這個東西的所有原始HTML文檔。

回答

5

看來這是一個與您使用的構造函數HtmlNode(HtmlNodeType, HtmlDocument, int)和方法InnerHtmlInnerText方法工作不一致的問題。 HtmlNode構造函數創建類型爲HtmlNode的節點(但將節點的類型設置爲傳遞的值)。如果你想獲得該節點的InnerHtmlInnerText,AgilityPack執行這樣的事情:

case HtmlNodeType.Text: 
    html = ((HtmlTextNode)this).Text; 

這實際上使你提到的InvalidCastException

爲了避免這種情況,我建議用HtmlDocument.CreateTextNode()方法使用創建文本節點的另一種方式:

foreach (var htmlNode in nodes) 
{ 
    var parent = htmlNode.ParentNode; 
    var newNode = doc.CreateTextNode(); 
    newNode.InnerHtml = "Test"; 
    parent.ReplaceChild(newNode, htmlNode); 
} 

這將正確地更換你的文本節點。