lxml xslt性能与xpath和replace

时间:2014-01-16 14:47:33

标签: python xslt xpath lxml

我有一些代码,作为其运行的一部分,它为了输出而采用HTML文档并将其转换为另一种形式。 (本质上是HTML到BBCode。)

我目前正在通过定义XPath字典和替换字典,然后使用lxml中的工具迭代字典:

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 个答案:

答案 0 :(得分:1)

问题1:是的,这可以通过XSLT实现。但似乎您只是忽略了字体,颜色和大小值。实际上,使用内联CSS解析这些值可能会因XSLT 1.0而变得复杂。

问题2:我认为它会明显加快。使用当前的解决方案,您必须多次迭代文档的所有节点(超过10次,AFAICS)。使用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')">...