HTMLAgility Pack:替换"混合类型"节点中的内容

Jak*_*son 1 c# dom html-agility-pack

我正在使用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);
}                
Run Code Online (Sandbox Code Playgroud)

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

<label>Email:<br><input name="txtID" type="text" id="txtID" class="input"></label>
Run Code Online (Sandbox Code Playgroud)

在替换之后,访问doc.DocumentNode.OuterHTML会导致以下异常:无法将类型为"HtmlAgilityPack.HtmlNode"的对象强制转换为"HtmlAgilityPack.HtmlTextNode".

我做错了吗?我无法真正去"清理"可能贯穿此内容的所有原始HTML文档.

Ale*_*lex 5

看来这是一个问题,HtmlNode(HtmlNodeType, HtmlDocument, int)你使用的构造函数和方法InnerHtmlInnerText方法之间的不一致.HtmlNode构造函数创建一个类型的节点HtmlNode(但将节点的类型设置为传递的值).如果你想获得InnerHtmlInnerText此节点,AgilityPack执行是这样的:

case HtmlNodeType.Text:
    html = ((HtmlTextNode)this).Text;
Run Code Online (Sandbox Code Playgroud)

这实际上导致InvalidCastException你提到.

为避免这种情况,我建议使用另一种使用HtmlDocument.CreateTextNode()方法创建文本节点的方法:

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

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