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

时间:2012-03-16 17:06:45

标签: 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);
}                

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

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

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

我是否错误地进行了更换?我无法真正去“清理”可能贯穿此内容的所有原始HTML文档。

1 个答案:

答案 0 :(得分: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);
}

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