lxml.etree._ElementTree.find()无法用于objectify.parse的结果

3 投票
1 回答
1349 浏览
提问于 2025-04-17 01:48
>>> from lxml import objectify
>>> from StringIO import StringIO
>>> f = StringIO("<root>data</root>")
>>> tree = objectify.parse(f)
>>> type(tree)
<type 'lxml.etree._ElementTree'>
>>> tree.find('root')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "lxml.etree.pyx", line 1944, in lxml.etree._ElementTree.find (src/lxml/lxml.etree.c:45105)
TypeError: find() takes exactly one argument (2 given)
>>> tree.find()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "lxml.etree.pyx", line 1926, in lxml.etree._ElementTree.find (src/lxml/lxml.etree.c:44970)
TypeError: find() takes at least 1 positional argument (0 given)
>>> print tree.find.__doc__
find(self, path, namespaces=None)

        Finds the first toplevel element with given tag.  Same as
        ``tree.getroot().find(path)``.

        The optional ``namespaces`` argument accepts a
        prefix-to-namespace mapping that allows the usage of XPath
        prefixes in the path expression.

注意,tree.getroot().find 是可以用的,而 find 也可以在通过 etree.parse 创建的 _ElementTree 实例上使用。

主要的问题是:为什么同一个方法会抛出这两种互相排斥的异常?另外,虽然我可以使用 tree.getroot().find,但如果短一点的写法能正常工作,那我更喜欢用短的方式,所以我很好奇,这是不是 lxml 的一个 bug?

1 个回答

0

我们通过查看相关的源代码来解决这个谜团(开源软件万岁!):

def find(self, path, namespaces=None):
    u"""find(self, path, namespaces=None)

    Finds the first toplevel element with given tag.  Same as
    ``tree.getroot().find(path)``.

    The optional ``namespaces`` argument accepts a
    prefix-to-namespace mapping that allows the usage of XPath
    prefixes in the path expression.
    """
    self._assertHasRoot()
    root = self.getroot()
    if _isString(path):
        start = path[:1]
        if start == u"/":
            path = u"." + path
        elif start == b"/":
            path = b"." + path
    return root.find(path, namespaces)

"lxml.etree.pyx"文件中,第1926行是这个代码片段的第一行,第1944行是最后一行,所以实际上有两个不同的find方法。显然,objectify构建了一些不同的对象(因此这是lxml中的一个bug),这些对象不接受namespaces这个参数。如果你使用lxml.etree.parse来解析你的StringIO对象,API就能正常工作。

撰写回答