如何在lxml xpath查询中使用默认命名空间?

32

我有一个如下格式的XML文档:

<feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:gsa="http://schemas.google.com/gsa/2007">
  ...
  <entry>
    <id>https://ip.ad.dr.ess:8000/feeds/diagnostics/smb://ip.ad.dr.ess/path/to/file</id>
    <updated>2011-11-07T21:32:39.795Z</updated>
    <app:edited xmlns:app="http://purl.org/atom/app#">2011-11-07T21:32:39.795Z</app:edited>
    <link rel="self" type="application/atom+xml" href="https://ip.ad.dr.ess:8000/feeds/diagnostics"/>
    <link rel="edit" type="application/atom+xml" href="https://ip.ad.dr.ess:8000/feeds/diagnostics"/>
    <gsa:content name="entryID">smb://ip.ad.dr.ess/path/to/directory</gsa:content>
    <gsa:content name="numCrawledURLs">7</gsa:content>
    <gsa:content name="numExcludedURLs">0</gsa:content>
    <gsa:content name="type">DirectoryContentData</gsa:content>
    <gsa:content name="numRetrievalErrors">0</gsa:content>
  </entry>
  <entry>
    ...
  </entry>
  ...
</feed>

我需要在lxml中使用xpath检索所有entry元素。我的问题是我无法弄清如何使用空命名空间。我已尝试了以下示例,但均未成功。请给予建议。

import lxml.etree as et

tree=et.fromstring(xml)    

我尝试过的各种方法包括:

for node in tree.xpath('//entry'):
或者
namespaces = {None:"http://www.w3.org/2005/Atom" ,"openSearch":"http://a9.com/-/spec/opensearchrss/1.0/" ,"gsa":"http://schemas.google.com/gsa/2007"}

for node in tree.xpath('//entry', namespaces=ns):
或者
for node in tree.xpath('//\"{http://www.w3.org/2005/Atom}entry\"'):

目前我不知道该尝试什么,非常感谢任何帮助。


2
当你无法在未分配名称的默认命名空间中找到标签时,这确实感觉很奇怪。当我遇到这种情况时,我简直不敢相信自己的眼睛。 - Ivan
2个回答

50

类似以下代码应该可以正常工作:

import lxml.etree as et

ns = {"atom": "http://www.w3.org/2005/Atom"}
tree = et.fromstring(xml)
for node in tree.xpath('//atom:entry', namespaces=ns):
    print node

参见http://lxml.de/xpathxslt.html#namespaces-and-prefixes

另一种选择:

for node in tree.xpath("//*[local-name() = 'entry']"):
    print node

9
这里没有办法使用默认命名空间吗?我问这个问题是因为使用文档中实际出现的标签 <entry><atom:entry> 更容易。请注意,翻译时不能改变原意,也不要添加解释或其他内容。 - ewok
1
需要注意的是,在非命名空间文档中,tree.xpath("atom:entry") 是可行的,但在命名空间文档中却不行。你需要使用 //,像这样:tree.xpath("//atom:entry") - CodeMonkey
2
“local-name”提示是一个好的技巧,可以在命名空间元素中找到非命名空间元素。 - ghukill

2
使用 findall 方法。
for item in tree.findall('{http://www.w3.org/2005/Atom}entry'): 
    print item

5
这是一个有用的解决方法,但是在实际使用tree.xpath()时,是否可以在xpath表达式中使用命名空间呢? - ewok

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接