Skip to main content
 首页 » 编程设计

c#之HTML敏捷包 : Replacing content in a "mixed-type" node

2024年02月02日33zhwl

我正在使用 HTMLAgility Pack 对 HTML 输出进行一些即时修改——查找所有文本节点并替换它们:

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); 
}                 

但是如果文本节点不是父节点的唯一子节点,这似乎会导致问题。例如:

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

被替换后,访问doc.DocumentNode.OuterHTML会出现如下异常: 无法将“HtmlAgilityPack.HtmlNode”类型的对象转换为类型“HtmlAgilityPack.HtmlTextNode”。

我是否做错了替换?我真的不能去“清理”所有可能通过这个东西运行的原始 HTML 文档。

请您参考如下方法:

这似乎是您使用的 HtmlNode(HtmlNodeType, HtmlDocument, int) 构造函数与 InnerHtml 和 InnerText 之间不一致的问题方法有效。 HtmlNode 构造函数创建类型为 HtmlNode 的节点(但将节点类型设置为传递的值)。当你想得到这个节点的 InnerHtml 或 InnerText 时,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); 
} 

这将正确替换您的文本节点。