2009-08-23 20 views
29

mio file XML si presenta come la seguente:Utilizzando XPath in ElementTree

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

Tutto quello che voglio fare è estrarre il ListPrice.

Questo è il codice che sto usando:

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

Assolutamente nessuna uscita. Ho anche provato

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

Nessuna differenza.

Cosa sto sbagliando?

risposta

52

Ci sono 2 problemi che si hanno.

1) element contiene solo l'elemento radice, non in modo ricorsivo l'intero documento. È di tipo Elemento non ElementTree.

2) La stringa di ricerca deve utilizzare gli spazi dei nomi se si mantiene lo spazio dei nomi nell'XML.

Per risolvere problema # 1:

È necessario modificare:

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

a:

element = ET.parse(fp) 

Per fissare problema # 2:

È può decollare th e xmlns dal documento XML in modo che appaia così:

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

Con questo documento, è possibile utilizzare la seguente stringa di ricerca:

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

Il codice completo:

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 

alternativo risolvere il problema n. 2:

Altrimenti è necessario per specificare gli xmlns all'interno della stringa srearch per ogni elemento.

Il codice completo:

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 

Entrambi stampa:

+0

Grazie mille. Stava per sbattere la testa contro un muro ripetutamente. –

+6

Nessun problema, dovrebbero dare un esempio con namespace nella loro documentazione per find e findall. –

+0

beh, avrebbero potuto rendere questo più chiaro nella documentazione ... grazie! – jorrebor

6

Elemento albero utilizza gli spazi dei nomi in modo che tutti gli elementi nella vostra XML hanno nome come { http://webservices.amazon.com/AWSECommerceService/2008-08-19} Articoli

Quindi effettuare la ricerca include lo spazio dei nomi ad es.

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) 

dà l'elemento corrispondente a 2260

+0

Penso tu intenda: 2260 –

+0

Sì - pigrizia Ho appena visto Python stesso elemento Amounty e l'indirizzo non ho fatto il bit in più e vedere che teext l'elemento aveva – Mark

7
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 

Inoltre, è consigliabile utilizzare lxml. È molto più veloce.

from lxml import ElementTree as ET 
+0

mi sono appena spostato da xml a lxml e wooo che differenza di velocità ... lxml è molto più veloce e gestisce meglio gli spazi dei nomi. –

6

ho finito Depurando il xmlns dal XML grezzo così:

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

ovviamente molto attenti con questo, ma ha funzionato bene per me.

0

Uno dei approccio in avanti più dritto e funziona anche con Python 3.0 e altre versioni è come di seguito:

Ci vuole solo la radice e comincia a entrare in esso fino a quando si ottiene il tag specificato "Importo"

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) 
Problemi correlati