Utilizzando XPath in ElementTree
-
19-09-2019 - |
Domanda
Il mio file XML è simile al seguente:
<?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.
Che cosa sto facendo di sbagliato?
Soluzione
Ci sono 2 problemi che avete.
1) element
contiene solo l'elemento principale, non ricorsivamente l'intero documento. E 'di tipo elemento non ElementTree.
2) la stringa di ricerca ha bisogno di utilizzare gli spazi dei nomi se si mantiene lo spazio dei nomi in XML.
Per risolvere problema # 1:
È necessario modificare:
element = ET.parse(fp).getroot()
a:
element = ET.parse(fp)
Per risolvere problema # 2:
È possibile togliere i xmlns dal documento XML in modo che appaia in questo modo:
<?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
fix alternativo al problema # 2:
In caso contrario, è necessario specificare i 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
Sia stampa:
2260
Altri suggerimenti
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, è possibile utilizzare lxml . E 'il modo più veloce.
from lxml import ElementTree as ET
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} Voci
Quindi, rendere la ricerca includono lo spazio dei nomi per 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
Ho finito Depurando il xmlns dal XML grezzo così:
def strip_ns(xml_string):
return re.sub('xmlns="[^"]+"', '', xml_string)
Ovviamente essere molto attenti con questo, ma ha funzionato bene per me.
Uno dei approccio più avanti 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 la tag "Importo" specificato
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)