как использовать пустые пространства имен в запросе lxml xpath?

У меня есть 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>

Мне нужно получить все элементы entry, используя xpath в lxml. Моя проблема в том, что я не могу понять, как использовать пустое пространство имен. Я пробовал следующие примеры, но они не работают. Пожалуйста, порекомендуйте.

import lxml.etree as et

tree=et.fromstring(xml)    

Различные вещи, которые я пробовал:

for node in tree.xpath('//entry'):

or

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):

or

for node in tree.xpath('//\"{http://www.w3.org/2005/Atom}entry\"'):

На данный момент я просто не знаю, что попробовать. Любая помощь приветствуется.


person ewok    schedule 08.11.2011    source источник
comment
Действительно странно, что это не позволит вам найти теги в пространстве имен по умолчанию, которым не было присвоено имя. Я не поверил своим глазам, когда столкнулся с этим.   -  person Ivan    schedule 24.06.2019


Ответы (2)


Что-то вроде этого должно работать:

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
person mzjn    schedule 08.11.2011
comment
так что здесь нельзя использовать пространство имен по умолчанию? Я спрашиваю, потому что это упрощает использование фактического тега, как он появляется в документе, то есть <entry>, а не <atom:entry> - person ewok; 08.11.2011
comment
Важно отметить, что tree.xpath("atom:entry") не работает, а в документе без пространства имен работает tree.xpath("atom:entry"). Вам нужен // как в tree.xpath("//atom:entry"). - person CodeMonkey; 01.07.2016
comment
Совет local-name хорош для поиска элементов без пространства имен среди элементов с пространством имен. - person ghukill; 20.11.2018

Используйте метод findall.

for item in tree.findall('{http://www.w3.org/2005/Atom}entry'): 
    print item
person Seb    schedule 08.11.2011
comment
Это полезный обходной путь, но возможно ли использовать пространства имен в реальном выражении xpath, используя tree.xpath() - person ewok; 08.11.2011