web-dev-qa-db-ja.com

ElementTreeでXPathを使用する

私の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')

変わりはない。

私は何を間違えていますか?

34
Ryan R. Rosario

あなたが持っている2つの問題があります。

1)elementには、ドキュメント全体を再帰的にではなく、ルート要素のみが含まれます。 ElementTreeではなくElementタイプです。

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の代替修正:

それ以外の場合は、各要素のsrearch文字列内に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

57
Brian R. Bondy
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
7
gonsalu

私はそのような未加工のxmlからxmlnsを取り除くことになりました:

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

明らかにこれには非常に注意しますが、私にとってはうまくいきました。

6
Franz

要素ツリーは名前空間を使用するため、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に対応する要素を与える

6
Mark

最も単純なアプローチの1つであり、python 3.0および他のバージョンでも以下のように動作します。

ルートを取得し、指定された「Amount」タグを取得するまで取得を開始します

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