【问题标题】:lxml xslt performance versus xpath and replacelxml xslt 性能与 xpath 和替换
【发布时间】:2014-01-16 14:47:32
【问题描述】:

我有一些代码,作为其运行的一部分,为了输出,它获取一个 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 完成所有这些操作,即用非标准标签替换一些标签,并在保留其文本或尾部内容的同时彻底删除标签。

其次,我想知道这样做是否可以显着提高性能?我怀疑是这样,但是,我似乎在互联网上找不到太多关于此的信息。

【问题讨论】:

    标签: python xslt xpath lxml


    【解决方案1】:

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

    问题 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')">...
    

    【讨论】:

    • 感谢您的回复!我实际上并没有完全忽略颜色、字体和大小值;我只是先用 XPath 稍微清理一下它们,然后用正则表达式将它们替换为所需的[color=#123456] 形式。此外,我将如何重写它以便它只通过文档一次?除了一些笨拙的状态机之外,我真的没有看到其他方法。
    • 哦。我可以遍历整个文档,并根据测试字典测试每个节点。不过,这会比测试每个 XPath 更便宜吗?
    • 经过仔细考虑,如果对 C 的调用本身很昂贵,我完全不确定迭代文档并在每个节点上调用测试会更便宜。我肯定会更多地以这种方式调用 C 函数!
    猜你喜欢
    • 2014-01-10
    • 1970-01-01
    • 2012-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-07
    相关资源
    最近更新 更多