Seite 1 von 1

suche funktion für etree

Verfasst: Sonntag 28. August 2011, 12:38
von anton_82
Hallo,
pase eine XML datei mit etree.
ein Knoten <HZ> kommt im Knoten <HI> verschieden of vor.
Das Problem, das ich habe liegt bei der Anzahl der Elemente von HZ, da diese variiert.
Beispiel:

Code: Alles auswählen

<HI>
	<HZ>
		<HZ001>Eins</HZ001>
		<HZ003>Drei</HZ003>
		<HZ004>Vier</HZ004>
	</HZ>
	<HZ>
		<HZ001>Eins</HZ001>
		<HZ002>Zwei</HZ002>
		<HZ003>Drei</HZ003>
		<HZ004>Vier</HZ004>
	</HZ>
	<HZ>
		<HZ001>Eins</HZ001>
		<HZ003>Drei</HZ003>
	</HZ>
<HI>
Ich möchte die Elemente von HZ nacheinanader in eine Liste speichern und dieser später abarbeiten. Dafür sollen der Liste pro HZ vier weitere Positionen hizugefügt werden, die den Text des jeweiligen Tags enthalten.
Falls das gesuchte Element (und somit auch der Text) nicht vorhanden ist soll in die Liste eine 0.

Habe bislang verschiedene if/else und try/catch konstrukte probiert, funktionieren aber nicht: Der Lister werden zuviele oder keine Stellen hinzugefügt.
Ich habe versucht, mit der Funktion iselelemnt("HZ001") zu arbeiten - fall der wert True ist, den Text der Liste anhängen, andernfalls eine Null anhängen. Das klappt nicht.
Beispiel:

Code: Alles auswählen

                                    if (elementHz.iselement("HZ001")) == True :
                                         tag = elementHz.text
                                         hzContentList.append(tag)
                                    elif (elementHz.iselement("HZ001")) == False :
                                        hzContentList.append(0)
                                    
                                    elif (elementHz.iselement("HZ0002")) == True :
                                         tag = elementHz.text
                                         hzContentList.append(tag)
                                    elif (elementHz.iselement("HZ0002")) == False :
                                        hzContentList.append(0)

Code: Alles auswählen

AttributeError: _ElementInterface instance has no attribute 'iselement'

Gibt es eine Funktion (für Python ab Version 2.5), die das kann oder hat jemand eine andere Idee, wie ich das Problem in den Griff bekomme?

Gruß,
Anton

Re: suche funktion für etree

Verfasst: Sonntag 28. August 2011, 13:26
von snafu
Naja, statt einer 0 würde ich hier eher zu `None` raten. Sofern du die Elemente weiterverarbeiten willst, solltest du auch besser das gesamte Element speichern. Das sähe dann (als hässlicher Prototyp) so aus:

Code: Alles auswählen

>>> xml = """\
... <HI>
...    <HZ>
...       <HZ001>Eins</HZ001>
...       <HZ003>Drei</HZ003>
...       <HZ004>Vier</HZ004>
...    </HZ>
...    <HZ>
...       <HZ001>Eins</HZ001>
...       <HZ002>Zwei</HZ002>
...       <HZ003>Drei</HZ003>
...       <HZ004>Vier</HZ004>
...    </HZ>
...    <HZ>
...       <HZ001>Eins</HZ001>
...       <HZ003>Drei</HZ003>
...    </HZ>
... </HI>"""
>>> from xml.etree import ElementTree as etree
>>> tree = etree.fromstring(xml)
>>> hz_elems = tree.findall('HZ')
>>> hz_names = ('HZ001', 'HZ002', 'HZ003', 'HZ004')
>>> [hz_elems[0].find(name) for name in hz_names]
[<Element HZ001 at 92de3cc>, None, <Element HZ003 at 92de4ec>, <Element HZ004 at 92de58c>]
>>> [hz_elems[0].findtext(name) for name in hz_names] # wenn's denn sein muss...
['Eins', None, 'Drei', 'Vier']

Re: suche funktion für etree

Verfasst: Sonntag 28. August 2011, 13:26
von Hyperion
Wieso vergleichst Du nicht mit dem Tagnamen?:

Code: Alles auswählen

In [13]: for hz in doc.findall("HZ"):
   ....:     for child in hz.getchildren():
   ....:         print child.tag
   ....:         
   ....:         
HZ001
HZ003
HZ004
HZ001
HZ002
HZ003
HZ004
HZ001
HZ003
Muss es denn dann eine Liste sein oder geht auch ein Dict? Denn das könntest Du ja per `collections.defaultdict` entsprechend mit "0"en vorbereiten und beim Auftreten eines Keys ("HZ00x") den Wert in des Dict schreiben.

Re: suche funktion für etree

Verfasst: Sonntag 28. August 2011, 14:07
von anton_82
Hallo,
Danke für die schnelle Antworten.

Sorry, ich war bei der Problembeschreibung etwas schlampig :oops:
Das Gesamtdokument ist so aufgebaut:

Code: Alles auswählen

<Data>
	<Hg>
		<HI>
			<HZ>
			</HZ>
			...
		</HI>	
	</Hg>
	<Hg>
		...
	</Hg>	
</Data>
Dabei kommt <HG> bei meinem Haupdokument ca. 3400 mal vor, insgesamt hat der Datensatz gut mehr als 840.000 Zeilen (Geodaten halt)
Am Ende jedes <HG> soll die Liste verabeitet werden, weshalb ich michf sequetielles durchlaufen entschied. Ich hatte mal ne methode mit .findall implementiert, jedoch wurde es mit meinen 2GB Arbeitsspeicher etwas eng...

Habe es erstmal versucht, so zu lösen:

Code: Alles auswählen

elif elementHi.tag =="HZ":
                                hzList = elementHi.getchildren()    
                                for elementHz in hzList:
                                    
                                    if elementHz.tag  == "HZ001":
                                        tag = elementHz.text
                                        hzContentList.append(tag)
                                    elif elementHz.tag == "HZ002":
                                        tag = elementHz.text
                                        hzContentList.append(tag)
                                    elif elementHz.tag == "HZ008":
                                        tag = elementHz.text
                                        hzContentList.append(tag) 
                                    elif elementHz.tag == "HZ010":
                                        tag = elementHz.text
                                        hzContentList.append(tag) 
Problemm : Es Gibt leider nur einen Listeneintrag, wenn das element vorhanden ist.
Kann ich dass den nicht irgendwie modifizieren, dass es immer einen Eintrag gibt? (Oder seh ich es einfach nur nicht?)
Werde die Dic Variante noch ausprobieren.

"Hässliche Prototypen" sind voll okay - Refaktoring kommt eh erst, wenn' läuft - mir erstmal wichtig ist, es überhaupt ans laufen zu bekommen.

Malschauen, wie ich eure Ideen da kombinieren kann, nochmals Danke dafür.
Falls jemand noch spontan nen anderen Einfall hat, gerne her damit.

Gruß,
Anton

Re: suche funktion für etree

Verfasst: Sonntag 28. August 2011, 14:38
von snafu
Ich habe doch schon gezeigt, wie man Platzhalter für nicht vorhandene Einträge erhält.

`.findall()` lässt sich zumindest ab Python 2.7 durch iterfind() ersetzen, um speicherschonend zu arbeiten. Ansonsten musst du dir das halt nachbauen.