2009-08-23 18 views
29

Meine XML-Datei sieht wie folgt aus:Mit 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> 

Alles, was ich tun möchte, ist die Listprice zu extrahieren.

Dies ist der Code ich verwende:

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

Absolut keine Ausgabe. Ich versuchte auch

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

Kein Unterschied.

Was mache ich falsch?

Antwort

52

Es gibt 2 Probleme, die Sie haben.

1) element enthält nur das Wurzelelement, nicht rekursiv das gesamte Dokument. Es ist vom Typ Element nicht ElementTree.

2) Ihre Suchzeichenfolge muss Namespaces verwenden, wenn Sie den Namespace im XML beibehalten.

Zum Problem # beheben 1:

Sie müssen sich ändern:

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

zu:

element = ET.parse(fp) 

zu beheben Problem # 2:

Sie kann th ausziehen e Xmlns aus dem XML-Dokument so sieht es wie folgt aus:

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

Mit diesem Dokument, das Sie die folgende Suchzeichenfolge verwenden:

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

Der vollständige Code:

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 

Alternate fix to problem # 2:

Sonst brauchen Sie um die xmlns innerhalb der search-Zeichenfolge für jedes Element anzugeben.

Der vollständige Code:

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 

Beide Druck:

+0

Vielen Dank. War kurz davor meinen Kopf gegen eine Wand zu schlagen. –

+6

Kein Problem, sie sollten ein Beispiel mit Namespaces in ihrer Dokumentation zum Suchen und Finden geben. –

+0

nun, sie hätten das in der Dokumentation deutlicher machen können ... danke! – jorrebor

6

Element Baum verwendet Namespaces, so dass alle Elemente in Ihrem XML-Namen wie haben { http://webservices.amazon.com/AWSECommerceService/2008-08-19} Artikel

So ist die Suche machen umfassen den Namespace z.B.

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) 

um das Element 2260

+0

Ich denke du meinst: 2260 –

+0

Ja - lazyness Ich sah nur Python gleiche Element Amounty und die Adresse, die ich nicht das bisschen mehr zu tun haben und sehen, was das Element teext – 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 

auch entsprechend gibt, betrachten lxml verwenden. Es ist viel schneller.

from lxml import ElementTree as ET 
+0

hatte ich gerade von xml bewegt lxml und wooo, was für ein Unterschied in der Geschwindigkeit ... lxml ist viel schneller und behandelt Namespaces besser. –

6

I beenden die xmlns aus dem rohen xml wie das Strippen up:

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

Offensichtlich mit diesem sehr vorsichtig sein, aber es funktionierte gut für mich.

0

Einer der direkteste Ansatz und arbeitet auch mit Python 3.0 und anderen Versionen ist wie folgt:

Es dauert nur die Wurzel und beginnt in sie bekommen, bis wir das angegeben „Betrag“ Tag erhalten

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)