Seite 1 von 1

Fragen zum XML auslesen per Modul

Verfasst: Freitag 9. Februar 2007, 13:04
von Xenon-777
also ... ich hab mich mal 3-4 Tage durchs Netz gekämpft um mal so was ähnliches wie ein XML zu Dict Modul zu bauen. Etwas ähnliches hatte ich sogar schon gefunden nur leider sehr fehleranfällig und ohne das Attribute unterstützt werden. So ... hier mal das Modul:

Code: Alles auswählen

from xml.dom.minidom import parse,parseString
from urllib2         import urlopen
from os              import open

def xmlopen(url,enc=None):

	if url[:7].lower() == "http://":
		xmlfd = urlopen(url)
	else:
		xmlfd = open(url,"r")
	if enc == None:
		xmlhl = xmlhead(xmlfd)
		enc = xmlhl['encoding']
		# leider laest sich das bearbeitete xml danach nicht mehr parsen weswegen es neu goeffnet werden muss 
		xmlfd.close()
		xmlfd = urlopen(url)
	xmldoc = parse(xmlfd)
	xmlfd.close()

	return bibxml(xmldoc,enc)

def xmlhead(xmlfd): # Auswerten der Header-Variablen

	xmlc = ""
	xmlhead = ""
	while xmlc != ">":
		xmlhead = xmlhead + xmlc
		xmlc = xmlfd.read(1)
	xmlhead = xmlhead + " />"
	xmlhead = xmlhead.replace("?","")

	attribl = {} 
	head = parseString(xmlhead)
	for attribut in head.childNodes[0].attributes.keys():
		attribl[head.childNodes[0].attributes[attribut].name.encode()] = head.childNodes[0].attributes[attribut].value.encode()
	return attribl

def bibxml(xmldoc,enc):

	name = ""
	bibnodes = {}

	for childnode in xmldoc.childNodes:

		if childnode.nodeType == 1: # Node ist ein Tag
			name = childnode.nodeName.encode(enc)
			# Inhalt
			if childnode.hasChildNodes():
				value = bibxml(childnode,enc)
			elif childnode.nodeValue == None:
				value = childnode.nodeValue
			else:
				value = childnode.nodeValue.encode(enc)

			# Attribute
			if childnode.attributes.keys() != []:
				attribbib = {}
				for attribut in childnode.attributes.keys():
					aname  = childnode.attributes[attribut].name.encode(enc)
					avalue = childnode.attributes[attribut].value.encode(enc)
					attribbib[aname] = avalue
				if value != None:
					value = [{'attribut':attribbib},value]
				else:
					value = {'attribut':attribbib}

			# Eintragen von einen bibliotheks-Eintrag ( zugegeben -> geklaut ;P )
			if value != None:
				if name in bibnodes: 
					if isinstance(bibnodes[name], dict):
						# there is multiple instances of this node - convert to list
						bibnodes[name] = [bibnodes[name]]
					bibnodes[name].append(value)
				else:
					bibnodes[name] = value

		if ((childnode.nodeType == 3) or (childnode.nodeType == 4)): # Node ist ein Text
			if childnode.nodeValue != None:
				value = childnode.nodeValue.encode(enc).replace("\n","")
				value = value.replace("\t","")
				value = value.replace(" ","")
				if value == "":
					continue
			bibnodes = childnode.nodeValue.encode(enc)

	return bibnodes
So ... 2 Probleme hab ich in den code:

1. Wie der aufmerksame Beobachter sehen kann lese ich, falls kein encoding angegeben ist, den ersten Tag aus, lösche die ?, setze ein /> hinten dran und parse das zu einen dict um das encoding, und andere dokumet deklarationen, zu erhalten. Problem bei den ganzen, an gelesenen fd mag der xml.dom parser nicht mehr und .seek() ist bei urlopen nicht möglich. Irgendwelche Ideehen wie man das besser machen kann als die quelle 2 mal zu öffnen? Erstellen einer Datei ist auf einen Unix System zumindest mal heikel und würde ich gerne vermeiden.

2. Es ist ein Fehler in Modul. Das Modul funktioniert soweit, nur bei folgender Konstellation versagt es:

<tag1>
<tag2 attr1="bla" attr2="blub">text1</tag2>
<tag2 attr1="bla" attr2="blub">text2</tag2>
<tag2 attr1="bla" attr2="blub">text3</tag2>
</tag1>

Normalerweise sollte dann in dic es so aussehen das x['tag1']['tag2'] eine liste ist mit 3 Elemente, jedes Elemet wider eine liste mit 2 Elementen wo [0] die Attribute sind und [1] der text. Leider verpackt er das erste auftreten von tag2 falsch so das x['tag1']['tag2'] eine liste aus 4 Elementen ist wo das [0] die Attribute des ersten auftreten von tag2 sind, [1] der text dazu und erst dann die listen für die weiteren tag2 koreckt eingebaut werden. Wo der fehlter liegt hab ich nicht raus gefunden. Vileicht sieht ihn ja einer von euch.

---8<------------

Oha ... ich sehe gerade das es auch mit Dateien so wohl nicht funktionieren würde. das start def werde ich wohl nochmal umschreiben müssen.
Aber trotzdem bin ich für jeden tip dankbar der das Teil optimirt.

Edit (Leonidas): Code-Highlighting eingeschaltet.

Verfasst: Freitag 9. Februar 2007, 17:12
von Leonidas
Hallo Xenon-777, willkommen im Forum,

Kurze Gegenfrage: Warum nicht einfach ElementTree nehmen? Das unterstützt XML wunderbar, funktioniert schnell und ist bei Python mitgeliefert.

Verfasst: Freitag 9. Februar 2007, 17:47
von Xenon-777
ööööömmmm ... weil es mir bei meiner ganzen Suche in Netz (und meinen tableiste in Firefox ist mitlerweile schon 8-9 Zeilen lang) nie einer empfohlen hat

Eines meiner hauptprobleme mit Python, so sehr ich die sprache auch liebe, ist die documentation. Fraglich ob eine Funktion überhaubt komplet und verständlich sowie mit allen anwendungsmöglichkeiten beschriben wird. Ich hab das xml-dom Wissen das da in Modul steckt locker aus 15-20 verschidenen Qwellen zusammengesucht. Da ist php mit www-php.org richtig gehend vorbildlich.

Aber danke für die Begrüsung, und danke für den tip ... dann mach ich mich mal wider auf die suche :)

Verfasst: Freitag 9. Februar 2007, 18:06
von gerold
Xenon-777 hat geschrieben:dann mach ich mich mal wider auf die suche :)
Hallo Xenon-777!

Willkommen im Python-Forum!

Jetzt bist du ja im Python-Forum gelandet. Die Forensuche bietet Zugang zu geballtem Python-Wissen. :wink:

Hier ist ein Beispiel zur Verwendung von ElementTree:
http://www.python-forum.de/post-57056.html#57056

Dann habe ich noch zwei Links:
- http://docs.python.org/lib/module-xml.e ... tTree.html
- http://effbot.org/zone/element-index.htm

mfg
Gerold
:-)