我正在使用 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);
}
这将正确替换您的文本节点。
