suche funktion für etree

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
anton_82
User
Beiträge: 8
Registriert: Sonntag 17. Juli 2011, 11:49

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
Benutzeravatar
snafu
User
Beiträge: 6833
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

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']
Zuletzt geändert von snafu am Sonntag 28. August 2011, 13:28, insgesamt 1-mal geändert.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

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.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
anton_82
User
Beiträge: 8
Registriert: Sonntag 17. Juli 2011, 11:49

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
Benutzeravatar
snafu
User
Beiträge: 6833
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

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