Использование XPath в ElementTree
Мой XML файл выглядит следующим образом:
<?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')
Никакой разницы.
Что я делаю неправильно?
Ответы
Ответ 1
Есть 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
Альтернативное исправление проблемы # 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
Обе печати:
2260
Ответ 2
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
Ответ 3
Дерево элементов использует пространства имен, поэтому все элементы в вашем 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
Ответ 4
В итоге я удалил xmlns из необработанного xml следующим образом:
def strip_ns(xml_string):
return re.sub('xmlns="[^"]+"', '', xml_string)
Очевидно, будьте очень осторожны с этим, но это сработало для меня.
Ответ 5
Один из самых простых подходов и работает даже с 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)