2009-08-23 4 views
29

Мой файл XML выглядит следующим образом:Использование XPath в ElementTree

<?xml version="1.0"?> 
<ItemSearchResponse xmlns="http://webservices.amazon.com/AWSECommerceService/2008-08-19"> 
    <Items> 
    <Item> 
     <ItemAttributes> 
     <ListPrice> 
      <Amount>2260</Amount> 
     </ListPrice> 
     </ItemAttributes> 
     <Offers> 
     <Offer> 
      <OfferListing> 
      <Price> 
       <Amount>1853</Amount> 
      </Price> 
      </OfferListing> 
     </Offer> 
     </Offers> 
    </Item> 
    </Items> 
</ItemSearchResponse> 

Все, что я хочу сделать, это извлечь ListPrice.

Это код, я использую:

>> from elementtree import ElementTree as ET 
>> fp = open("output.xml","r") 
>> element = ET.parse(fp).getroot() 
>> e = element.findall('ItemSearchResponse/Items/Item/ItemAttributes/ListPrice/Amount') 
>> for i in e: 
>> print i.text 
>> 
>> e 
>> 

Абсолютно не выход. Я также пробовал

>> e = element.findall('Items/Item/ItemAttributes/ListPrice/Amount') 

Без разницы.

Что я делаю неправильно?

ответ

52

Есть 2 проблемы, которые у вас есть.

1) element содержит только корневой элемент, а не рекурсивно весь документ. Это тип Element, а не ElementTree.

2) Ваша строка поиска должна использовать пространства имен, если вы сохраняете пространство имен в XML.

Чтобы исправить проблему # 1:

Вам нужно изменить:

element = ET.parse(fp).getroot() 

к:

element = ET.parse(fp) 

Чтобы устранить проблему # 2:

вас может взлететь е XMLNS из документа XML, так это выглядит следующим образом:

<?xml version="1.0"?> 
<ItemSearchResponse> 
    <Items> 
    <Item> 
     <ItemAttributes> 
     <ListPrice> 
      <Amount>2260</Amount> 
     </ListPrice> 
     </ItemAttributes> 
     <Offers> 
     <Offer> 
      <OfferListing> 
      <Price> 
       <Amount>1853</Amount> 
      </Price> 
      </OfferListing> 
     </Offer> 
     </Offers> 
    </Item> 
    </Items> 
</ItemSearchResponse> 

С помощью этого документа можно использовать следующую строку для поиска:

e = element.findall('Items/Item/ItemAttributes/ListPrice/Amount') 

Полный код:

from elementtree import ElementTree as ET 
fp = open("output.xml","r") 
element = ET.parse(fp) 
e = element.findall('Items/Item/ItemAttributes/ListPrice/Amount') 
for i in e: 
    print i.text 

Alternate исправить проблему № 2:

В противном случае вам необходимо для указания xmlns внутри строки srearch для каждого элемента.

Полный код:

from elementtree import ElementTree as ET 
fp = open("output.xml","r") 
element = ET.parse(fp) 

namespace = "{http://webservices.amazon.com/AWSECommerceService/2008-08-19}" 
e = element.findall('{0}Items/{0}Item/{0}ItemAttributes/{0}ListPrice/{0}Amount'.format(namespace)) 
for i in e: 
    print i.text 

И печать:

+0

Огромное спасибо. Я собирался несколько раз ударить головой о стену. –

+6

Нет проблем, они должны привести пример с пространствами имен в своей документации для find и findall. –

+0

ну, они могли бы сделать это более ясным в документации ... спасибо! – jorrebor

6

Элемент дерева использует пространство имен, так что все элементы в вашем XML имеют имя, как { http://webservices.amazon.com/AWSECommerceService/2008-08-19} Позиции

Так что сделайте поиск в пространстве имен , например.

search = '{http://webservices.amazon.com/AWSECommerceService/2008-08-19}Items/{http://webservices.amazon.com/AWSECommerceService/2008-08-19}Item/{http://webservices.amazon.com/AWSECommerceService/2008-08-19}ItemAttributes/{http://webservices.amazon.com/AWSECommerceService/2008-08-19}ListPrice/{http://webservices.amazon.com/AWSECommerceService/2008-08-19}Amount' 
element.findall(search) 

дает элемент, соответствующий 2260

+0

Я думаю, что вы имеете в виду: 2260 –

+0

Да - ленивость Я только что видел python тот же самый элемент Сумка и адрес Я не делал лишний бит и вижу, что teext Element имеет – Mark

7
from xml.etree import ElementTree as ET 
tree = ET.parse("output.xml") 
namespace = tree.getroot().tag[1:].split("}")[0] 
amount = tree.find(".//{%s}Amount" % namespace).text 

Кроме того, рассмотреть вопрос об использовании lxml. Это быстрее.

from lxml import ElementTree as ET 
+0

Я просто перешел из xml в lxml и wooo, какая разница в скорости ... lxml быстрее работает и лучше управляет пространствами имен. –

6

Я в конечном итоге зачистки из Xmlns из необработанного XML, как, что:

def strip_ns(xml_string): 
    return re.sub('xmlns="[^"]+"', '', xml_string) 

Очевидно быть очень осторожным с этим, но она работала хорошо для меня.

0

Одним из наиболее прямой вперед подход и работает даже с Python 3.0 и других версий, как показано ниже:

Он просто берет корень и начинает получать в него, пока мы не получим указанный «Сумма» метки

from xml.etree import ElementTree as ET 
tree = ET.parse('output.xml') 
root = tree.getroot() 
#print(root) 
e = root.find(".//{http://webservices.amazon.com/AWSECommerceService/2008-08-19}Amount") 
print(e.text) 
Смежные вопросы