【发布时间】:2014-04-11 05:24:46
【问题描述】:
我需要先转义 HTML 标签的黑名单,然后再在网页中显示。选择性的原因是允许保留格式(正文、斜体、字体等),但不允许保留任何会“破坏”页面的标签(脚本、元数据等)。
考虑了一段时间后,我想出了两种方法:
- RegEx -- 几乎每个人都会告诉你,使用 RegEx 处理 HTML 是一个坏主意
- HtmlAgilityPack
我认为我最好的(也是唯一的)解决方案是将字符串加载到 HtmlAgilityPack 中并通过子节点递归循环。对于每个节点,我会检查它是否在指定的黑名单上。如果是,我将转义打开(如果存在则关闭)节点,然后处理InnerHtml。如果它不在列表中,则在仍在处理InnerHtml 的同时按原样输出节点。
所以,给定以下(非常简单的)来源
The quick <b style='padding: 0 25em;'>brown</b> fox <b>jumped <i>over</i> the <meta http-equiv='refresh' /> moon</b>.
我需要以下输出
The quick <b style='padding: 0 25em;'>brown</b> fox <b>jumped <i>over</i> the <meta http-equiv='refresh' /> moon</b>.
经过大量研究,我遇到了一些问题、问题和障碍。
-
HtmlAgilityPack是满足此要求的最佳库吗? - 递归解决方案是唯一的方法吗?我想使用
.Descendants()方法,因为它通过内部递归返回所有节点的扁平列表,但这会导致重复的内容。使用上面的示例,<i>over</i>节点是第二个 b 节点的InnerHtml的一部分,但在 Descendants 集合中也成为其自己的节点。 - 我可能缺少正确的方法或属性,但我找不到在不包含 InnerHtml 的情况下输出 仅 开始和结束标记的方法。我的用例是将开始标记(包括所有属性)输出为转义字符串,输出递归处理的 InnerHtml,然后输出转义结束标记。我想我可以通过使用不同的属性(名称、ID、属性等)来构建自己的输出,但我认为这已经可用。
在我看来,这个方法看起来有点像这样
public string EscapeHtmlTags(string value, ICollection<string> tags) {
var doc = new System.Text.StringBuilder();
doc.LoadHtml(doc);
if (tags.Contains(doc.DocumentNode.Name, StringComparer.CurrentCultureIgnoreCase)) {
// output opening tag as escaped string ????
EscapeHtmlTags(doc.DocumentNode.InnerHtml, tags);
// output closing tag as escaped string ????
}
else {
// output opening tag as is ????
EscapeHtmlTags(doc.DocumentNode.InnerHtml, tags);
// output closing tag as is ????
}
}
当然我仍然需要添加错误处理,并且可能以不同的方式处理各种 NodeType,并且可能添加一个 StringBuilder 实例来收集输出,等等......我什至可以采用克隆和替换现有的方法文档中的节点。
有什么想法或想法吗?
【问题讨论】:
-
我一般不喜欢正则表达式,尤其是不喜欢使用正则表达式解析 HTML,但在这种特殊情况下,我认为可以使用它,因为现有的 html 层次结构不是很重要,你基本上只想用
&lt替换所有<,而不是任何白名单标签。 -
@GolezTrol - 我最终听从了你的建议并使用了 RegEx。控制 HtmlAgilityPack 输出的限制太多了。随意重新发布作为答案,以便我给你信用。
-
谢谢。你可以给自己的信用。我只同意你自己已经想出来的一种方法。 :)
标签: html xml html-agility-pack