Python lxml-xslt性能与xpath和replace
我有一些代码,作为其运行的一部分,它将HTML文档转换为另一种形式以便于输出。(基本上是HTML到BBCode。) 我目前正在通过定义XPath和替换的字典来实现这一点,然后使用lxml中的工具对字典进行迭代:Python lxml-xslt性能与xpath和replace,python,xslt,xpath,lxml,Python,Xslt,Xpath,Lxml,我有一些代码,作为其运行的一部分,它将HTML文档转换为另一种形式以便于输出。(基本上是HTML到BBCode。) 我目前正在通过定义XPath和替换的字典来实现这一点,然后使用lxml中的工具对字典进行迭代: change_xpaths = { XPath(".//span[contains(@style, 'font')]") : "font", XPath(".//span[contains(@style, 'colo
change_xpaths = {
XPath(".//span[contains(@style, 'font')]") : "font",
XPath(".//span[contains(@style, 'color')]") : "color",
XPath(".//span[contains(@style, 'size')]") : "size"
}
replace_xpaths = {
XPath(".//span[@style='text-decoration: underline']") : "u",
XPath(".//span[@style='text-decoration: line-through']") : "s",
XPath(".//div[@style='padding-left: 30px']") : "remove"
}
def _clean_text(cls, raw):
for ele in cls.struck_through_xpath(raw):
ele.getparent().remove(ele)
for xp, repl in cls.replace_xpaths.items():
for ele in xp(raw):
ele.attrib.pop("style")
ele.tag = repl
for xp, chng in cls.change_xpaths.items():
for ele in xp(raw):
ele.tag = chng
for br in raw.xpath(".//br"):
try:
br.tail = "\n" + br.tail
except TypeError:
br.tail = "\n"
strip_elements(raw, 'img', with_tail = False)
strip_elements(raw, 'br', with_tail = False)
strip_tags(raw, 'remove')
(这确实是类定义的一部分。)
我知道我也可以使用xslt转换来实现这一点
首先,我想确认我确实可以用xslt完成这一切,也就是说,用非标准标记替换一些标记,完全删除标记,同时保留它们的文本或尾部内容
第二,我想知道这样做是否能显著提高绩效?但是,我怀疑是这样,我似乎在互联网上找不到太多关于这方面的信息。问题1:是的,XSLT可以做到这一点。但似乎您只是忽略了字体、颜色和大小值。实际上,使用XSLT1.0从内联CSS解析这些值可能会很复杂
问题2:我认为速度会明显加快。使用当前的解决方案,您必须多次迭代文档的所有节点(超过10次,AFAIC)。使用XSLT样式表,每个输入节点只访问一次。另外,由于lxml基于libxml2和libxslt,因此需要较少的对C-API的调用,根据我的经验,这可能会非常昂贵
OTOH,通过重写Python代码只扫描文档一次,可以获得类似的性能提升
如果进行多次转换,请确保只编译一次XSLT样式表
在XSLT级别也有一些可能的优化。最优雅的方法是编写如下模板:
<xsl:template match="span[contains(@style, 'font')]">...
<xsl:template match="span[contains(@style, 'color')]">...
<xsl:template match="span[contains(@style, 'size')]">...
。。。
...
...
对于每个元素名使用一个模板可能会更快一些,如下所示:
<xsl:template match="span">
<xsl:choose>
<xsl:when test="contains(@style, 'font')">...
<xsl:when test="contains(@style, 'color')">...
<xsl:when test="contains(@style, 'size')">...
...
...
...
感谢您的回复!实际上,我并不完全忽略颜色、字体和大小值;我只是先用XPath将它们清理一下,然后用正则表达式将它们替换成所需的[color=#123456]
。另外,我如何重写它,使它只在文档中浏览一次?除了一些笨重的状态机,我真的看不到其他方法。我可以遍历整个文档,并根据测试字典测试每个节点。但是,这会比测试每个XPath的成本更低吗?经过仔细考虑,如果对C的调用本身是昂贵的,我根本不确定迭代文档并在每个节点上调用测试的成本是否会更低。我肯定会用这种方式调用更多的C函数!