Использование XPath в ElementTree - PullRequest
34 голосов
/ 23 августа 2009

Мой 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')

Без разницы.

Что я делаю не так?

Ответы [ 5 ]

56 голосов
/ 24 августа 2009

У вас есть 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

7 голосов
/ 24 августа 2009
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
6 голосов
/ 27 апреля 2012

В итоге я удалил xmlns из необработанного xml вот так:

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

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

6 голосов
/ 24 августа 2009

Дерево элементов использует пространства имен, поэтому все элементы в вашем xml имеют такие имена, как {http://webservices.amazon.com/AWSECommerceService/2008-08-19}Items

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

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

1 голос
/ 13 октября 2017

Один из самых простых подходов и работает даже с 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)
...