修复Python lxml中的tostring()

时间:2011-01-05 22:52:01

标签: python xml lxml

当仅打印部分文档时,lxml的tostring()函数似乎很破碎。证人:

from lxml.html import fragment_fromstring, tostring
frag = fragment_fromstring('<p>This stuff is <em>really</em> great!')
em = frag.cssselect('em').pop(0)
print tostring(em)

我希望<em>really</em>,而是打印<em>really</em> great! 错误。最棒的 !' 是所选em的一部分。它不仅是错误的,它还是一个药丸,至少对于处理文档结构化的XML而言,这种结尾的文本很常见。

据我了解,lxml存储元素.tail属性中当前元素之后的所有自由文本。扫描tostring()的代码会将我带到ElementTree.py的_write()函数,该函数显然始终打印尾部。这是整个树的正确行为,但在渲染子树时不是最后一个元素,但它没有区别。

为了获得所选XML的正确无尾渲染,我尝试从头开始编写toxml()函数以在其中使用。它基本上有效,但在处理注释,处理指令,命名空间,编码,yadda yadda时有许多特殊情况。所以我改变了方向,现在只需背负tostring(),对其输出进行后处理,以删除有问题的.tail文本:

def toxml(e):
    """ Replacement for lxml's tostring() method that doesn't add spurious
    tail text. """

    from lxml.etree import tostring
    xml = tostring(e)
    if e.tail:
        xml = xml[:-len(e.tail)]
    return xml

一系列基本测试表明这很有效。

批评和/或建议?

1 个答案:

答案 0 :(得分:12)

xml = lxml.etree.tostring(e, with_tail=False)怎么样?

from lxml.html import fragment_fromstring
from lxml.etree import tostring
frag = fragment_fromstring('<p>This stuff is <em>really</em> great!')
em = frag.cssselect('em').pop(0)
print tostring(em, with_tail=False)

看起来在v2.0中添加了with_tail;你有旧版本吗?