21

我正在针对以下测试文档进行测试:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
   <head>
        <title>hi there</title>
    </head>
    <body>
        <img class="foo" src="bar.png"/>
    </body>
</html>

如果我使用 lxml.html 解析文档,我可以使用 xpath 获得 IMG:

>>> root = lxml.html.fromstring(doc)
>>> root.xpath("//img")
[<Element img at 1879e30>]

但是,如果我将文档解析为 XML 并尝试获取 IMG 标记,则会得到一个空结果:

>>> tree = etree.parse(StringIO(doc))
>>> tree.getroot().xpath("//img")
[]

我可以直接导航到元素:

>>> tree.getroot().getchildren()[1].getchildren()[0]
<Element {http://www.w3.org/1999/xhtml}img at f56810>

但这当然不能帮助我处理任意文件。我还希望能够查询 etree 以获得一个 xpath 表达式,该表达式将直接识别此元素,从技术上讲,我可以这样做:

>>> tree.getpath(tree.getroot().getchildren()[1].getchildren()[0])
'/*/*[2]/*'
>>> tree.getroot().xpath('/*/*[2]/*')
[<Element {http://www.w3.org/1999/xhtml}img at fa1750>]

但是,xpath 显然对于解析任意文档没有用处。

显然我在这里遗漏了一些关键问题,但我不知道它是什么。我最好的猜测是它与命名空间有关,但唯一定义的命名空间是默认命名空间,我不知道关于命名空间我还需要考虑什么。

那么,我错过了什么?

4

3 回答 3

27

问题是命名空间。当解析为 XML 时,img 标记位于http://www.w3.org/1999/xhtml命名空间中,因为这是元素的默认命名空间。您在没有命名空间中要求 img 标签。

试试这个:

>>> tree.getroot().xpath(
...     "//xhtml:img", 
...     namespaces={'xhtml':'http://www.w3.org/1999/xhtml'}
...     )
[<Element {http://www.w3.org/1999/xhtml}img at 11a29e0>]
于 2008-11-17T22:45:15.247 回答
7

XPath 认为所有无前缀的名称都在 "no namespace"中。

特别是规范说:

“节点测试中的 QName 使用表达式上下文中的命名空间声明扩展为扩展名称。这与对开始和结束标记中的元素类型名称进行扩展的方式相同,但使用 xmlns 声明的默认命名空间是未使用:如果 QName 没有前缀,则命名空间 URI 为空(这与扩展属性名称的方式相同)。"

请参阅问题及其解决方案的这两个详细说明:此处此处。解决方案是将前缀(与正在使用的 API)相关联,并使用它为 XPath 表达式中的任何未加前缀的名称添加前缀。

希望这有帮助。

干杯,

迪米特·诺瓦切夫

于 2008-11-17T23:13:07.153 回答
2

如果你打算只使用来自单个命名空间的标签,正如我在上面看到的那样,你最好使用 lxml.objectify。

在你的情况下,它就像

from lxml import objectify
root = objectify.parse(url) #also available: fromstring

您可以访问节点

root.html
body = root.html.body
for img in body.img: #Assuming all images are within the body tag

虽然它在 html 中可能没有太大帮助,但它在结构良好的 xml 中非常有用。

有关更多信息,请查看http://lxml.de/objectify.html

于 2011-05-12T13:06:52.507 回答