[英]Highlighting glossary terms inside a HTML document
我们有一个词汇表,最多可包含2000个术语(其中每个术语词可能包含一个,两个或三个词(用空格或破折号分隔)。
现在,我们正在寻找一种突出显示(较长)HTML文档(最多100 KB的HTML标记)中的所有术语的解决方案,以生成带有突出显示的术语的静态HTML页面。
一个有效的解决方案的约束是:大量的词汇表术语和冗长的HTML文档...有效的解决方案(在Python中)的蓝图是什么。
现在,我正在考虑使用lxml解析HTML文档,遍历所有文本节点,然后将每个文本节点中的内容与所有词汇表术语进行匹配。
客户端(浏览器)突出显示不是一个可行的选择,因为IE会抱怨长时间运行的脚本以及脚本超时...因此无法用于生产环境。
有更好的主意吗?
您可以使用解析器以递归方式导航树并仅替换由文本组成的标签。
这样做时,您仍然需要考虑几件事:
-并非所有文字都需要替换(例如内联javascript)
-文档的某些元素可能不需要解析(例如标题等)
这是一个快速且非生产就绪的示例,说明如何实现此目标:
html = """The HTML you need to parse"""
import BeautifulSoup
IGNORE_TAGS = ['script', 'style']
def parse_content(item, replace_what, replace_with, ignore_tags = IGNORE_TAGS):
for content in item.contents:
if isinstance(content, BeautifulSoup.NavigableString):
content.replaceWith(content.replace(replace_what, replace_with, ignore_tags))
else:
if content.name not in ignore_tags:
parse_content(content, replace_what, replace_with, ignore_tags)
return item
soup = BeautifulSoup.BeautifulSoup(html)
body = soup.html.body
replaced_content = parse_content(body, 'a', 'b')
这应该用“ b”替换出现的“ a”,但是保留以下内容:
-内联javascript或CSS(尽管内联JS或CSS不应出现在文档正文中)。
-标记中的参考,例如img,...
-标签本身
当然,然后,根据词汇表,您需要确保不要仅将单词的一部分替换为其他单词; 为此,使用content.replace的正则表达式很有意义。
我认为用客户端JavaScript突出显示是最好的选择。 它可以节省您的服务器处理时间和带宽,更重要的是,可以使html保持干净并可供那些不需要不必要标记的人使用,例如,在打印或转换为其他格式时。
为了避免超时,只需将作业拆分为多个块,然后在setTimeout的线程化函数中逐个处理它们。 这是这种方法的一个例子
function hilite(terms, chunkSize) {
// prepare stuff
var terms = new RegExp("\\b(" + terms.join("|") + ")\\b", "gi");
// collect all text nodes in the document
var textNodes = [];
$("body").find("*").contents().each(function() {
if (this.nodeType == 3)
textNodes.push(this)
});
// process N text nodes at a time, surround terms with text "markers"
function step() {
for (var i = 0; i < chunkSize; i++) {
if (!textNodes.length)
return done();
var node = textNodes.shift();
node.nodeValue = node.nodeValue.replace(terms, "\x1e$&\x1f");
}
setTimeout(step, 100);
}
// when done, replace "markers" with html
function done() {
$("body").html($("body").html().
replace(/\x1e/g, "<b>").
replace(/\x1f/g, "</b>")
);
}
// let's go
step()
}
像这样使用它:
$(function() {
hilite(["highlight", "these", "words"], 100)
})
如果您有任何问题,请告诉我。
如何遍历词汇表中的每个术语,然后对每个术语使用正则表达式查找HTML中所有出现的内容? 您可以将这些事件中的每一个都替换为用“突出显示”类包裹在范围中的术语,该类将被设置为具有背景色。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.