在ElementTree中使用XPath

48 投票
5 回答
79033 浏览
提问于 2025-04-15 13:49

我的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 个回答

7

元素树使用命名空间,所以你在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对应的元素。

9
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
from lxml import ElementTree as ET

另外,可以考虑使用 lxml。这个库的速度快得多。

71

你遇到了两个问题。

1) element 只包含根元素,而不是整个文档的内容。它的类型是 Element,而不是 ElementTree。

2) 如果你在 XML 中保留了命名空间,你的搜索字符串需要使用命名空间。

解决问题 #1:

你需要把:

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

改成:

element = ET.parse(fp)

解决问题 #2:

你可以把 XML 文档中的 xmlns 去掉,这样看起来就像这样:

<?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。

完整代码:

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

撰写回答