web-dev-qa-db-fra.com

Utilisation de XPath dans ElementTree

Mon fichier XML ressemble à ceci:

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

Tout ce que je veux faire, c'est extraire le ListPrice.

Voici le code que j'utilise:

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

Absolument aucune sortie. J'ai aussi essayé

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

Aucune différence.

Qu'est-ce que je fais mal?

37
Ryan R. Rosario

Vous avez 2 problèmes.

1) element ne contient que l'élément racine, pas récursivement tout le document. Il est de type Element et non ElementTree.

2) Votre chaîne de recherche doit utiliser des espaces de noms si vous conservez l'espace de noms dans le XML.

Pour résoudre le problème # 1:

Vous devez changer:

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

à:

element = ET.parse(fp)

Pour résoudre le problème # 2:

Vous pouvez retirer les xmlns du document XML pour qu'il ressemble à ceci:

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

Avec ce document, vous pouvez utiliser la chaîne de recherche suivante:

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

Le code complet:

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

Solution alternative au problème # 2:

Sinon, vous devez spécifier les xmlns à l'intérieur de la chaîne de recherche pour chaque élément.

Le code complet:

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

Les deux imprimés:

2260

61
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

Pensez également à utiliser lxml . C'est beaucoup plus rapide.

from lxml import ElementTree as ET
8
gonsalu

J'ai fini par retirer les xmlns du xml brut comme ça:

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

Évidemment, soyez très prudent avec cela, mais cela a bien fonctionné pour moi.

6
Franz

L'arborescence des éléments utilise des espaces de noms, donc tous les éléments de votre xml ont un nom comme { http://webservices.Amazon.com/AWSECommerceService/2008-08-19 } Éléments

Donc, faites en sorte que la recherche inclue l'espace de noms, par ex.

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 )

donne l'élément correspondant à 2260

6
user151019

L'une des approches les plus simples et fonctionne même avec python 3.0 et d'autres versions est comme ci-dessous:

Il prend juste la racine et commence à y entrer jusqu'à ce que nous obtenions la balise "Amount" spécifiée

 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
Chetan_Vasudevan