lxml.etree._ElementTree.find()无法用于objectify.parse的结果
>>> 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就能正常工作。