Seite 1 von 1
Parse SOAP xml fehler
Verfasst: Dienstag 4. September 2007, 09:23
von TwistedMetal
Hi profis,
Ich habe eine Applikation, die SOAP Requests akzeptiert. Ich bekomme SOAP Requests (xml) und will jetzt parsen so dass ich die daten, die die Tage enthalten rauskriege. Aber das funktioniert irgendwie nicht

Unten kann man den Code sehen:
Code: Alles auswählen
from xml.dom.minidom import parse, parseString
length = int(self.headers['content-length'])
xml_in = self.rfile.read(length)
doc_node = parseString(xml_in)
assert doc_node.documentElement.tagName == "class"
Ausgabe xml_in: (Diese Request ist durch SOAPUI generiert und gesendet)
Code: Alles auswählen
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:osf="http://MyNS:8080/TestService">
<soapenv:Header/>
<soapenv:Body>
<osf:getData>
<class>dfg</class>
<architecture>dfgd</architecture>
<filetype>ddg</filetype>
<repository>dfg</repository>
<yum_groups>dfg</yum_groups>
<yum_packages>dfgdfg</yum_packages>
<apt_packages>dfgdfg?</apt_packages>
</osf:getData>
</soapenv:Body>
</soapenv:Envelope>
Ausgabe doc_node:
und der Fehler:
Code: Alles auswählen
Exception happened during processing of request from ('127.0.0.1', 51887)
Traceback (most recent call last):
File "/usr/lib/python2.5/SocketServer.py", line 463, in process_request_thread
self.finish_request(request, client_address)
File "/usr/lib/python2.5/SocketServer.py", line 254, in finish_request
self.RequestHandlerClass(request, client_address, self)
File "osfarm.py", line 1032, in __init__
BaseHTTPServer.BaseHTTPRequestHandler.__init__(self, *params)
File "/usr/lib/python2.5/SocketServer.py", line 521, in __init__
self.handle()
File "/usr/lib/python2.5/BaseHTTPServer.py", line 316, in handle
self.handle_one_request()
File "/usr/lib/python2.5/BaseHTTPServer.py", line 310, in handle_one_request
method()
File "osfarm.py", line 1069, in do_POST
assert doc_node.documentElement.tagName == "class"
AssertionError
Ich bin ein Python und SOAP anfänger. Ich wurde mich sehr freuen wenn jemand mir helfen kann

Verfasst: Dienstag 4. September 2007, 09:52
von BlackJack
Ich weiss nicht, ob jemandem der SOAP verwenden will noch zu helfen ist.
Aber hilf Dir doch erst einmal selbst und schau mit einem ``print`` nach, was denn der `tagName` von dem `Node` ist. Ich würde mal auf 'soapenv' tippen und frage mich wieso Du da 'class' erwartest!?
Da es sich hier um Daten von aussen handelt würde ich hier kein ``assert`` benutzen. ``assert``\s sind eigentlich dazu da Bedingungen zu prüfen, die eigentlich nie falsch sein dürften. Eine ``if``-Abfrage die eine Ausnahme auslöst ist hier angebrachter.
Verfasst: Dienstag 4. September 2007, 10:01
von TwistedMetal
Das liefert einfach False.
aber wenn
Code: Alles auswählen
print doc_node.documentElement.tagName == "soapenv:Envelope"
Das liefert True
wie kann ich weiter nach unten bis class, architecture, filetype usw... zugreiffen?
Ich benutze SOAP weil ich muss. SOAP ist eine voraussetzung für dieses Projekt

Verfasst: Dienstag 4. September 2007, 10:11
von Joghurt
<offtopic>
Jeder, der sich mit SOAP beschäftigen muss, wird das hier nachvollziehen können:
http://wanderingbarque.com/nonintersect ... or-simple/
</offtopic>
Verfasst: Dienstag 4. September 2007, 10:15
von TwistedMetal
Ah Danke für den Link. Das ist wirklich super.
Aber irgendwie muss ich dieses Parsing noch schaffen

Update
Verfasst: Dienstag 4. September 2007, 10:38
von TwistedMetal
also ich habe jetzt den folgenden Code aufgebaut:
Code: Alles auswählen
rc = ""
nodelist = (doc_node.getElementsByTagName("osf:getData")[0]).childNodes
for node in nodelist:
if node.nodeType == node.TEXT_NODE:
rc = rc + node.data
print "printing" + rc
und die Ausgabe ist
Code: Alles auswählen
printing
printing
printing
printing
printing
printing
printing
printing
Was druckt er eigentlich zwischen printing? Und der Abstand vergrößert immer zwischen printing.
Aber wenn ich tagname als "class" nenne dann zeigt es die daten
Code: Alles auswählen
rc = ""
nodelist = (doc_node.getElementsByTagName("class")[0]).childNodes
for node in nodelist:
if node.nodeType == node.TEXT_NODE:
rc = rc + node.data
print "printing" + rc
Dann ist die Ausgabe richtig und ohne whitespace
Was ist los? Warum funktioniert die erste loop mit tagname "osf:getData" nicht? Any Ideas ??
Verfasst: Dienstag 4. September 2007, 11:16
von BlackJack
In der ersten Schleife gehst Du über die Kindknoten von `getDate` und gibst da die Textknoten aus. Das sind die Zeilenumbrüche und Leerzeichen *zwischen* den Elementen! Du willst aber die Textknoten die Kinder von den Elementen sind.
Die Ausgabe wird immer länger weil Du in `rc` bei jedem Schleifendurchlauf die neuen Daten an die alten anhängst und dann alles zusammen ausgibst.
Mit `minidom` musst Du über die Elemente gehen und bei denen dann die Textknoten abfragen:
Code: Alles auswählen
def main():
osf_namespace_uri = 'http://MyNS:8080/TestService'
doc_node = parseString(source)
get_data_node = doc_node.getElementsByTagNameNS(osf_namespace_uri,
'getData')[0]
for child in (node for node in get_data_node.childNodes
if node.nodeType == node.ELEMENT_NODE):
print child.nodeName, child.firstChild.nodeValue
Das Du nach 'osf:getData' suchst und nicht die `*NS` Funktion benutzt, ist übrigens nicht besonders robust. Wichtig ist die URI und nicht der Bezeichner der in dem Dokument "zufällig" dafür benutzt wird.
Zum Arbeiten mit XML würde ich aber `ElementTree` empfehlen. Das hat eine schönere API als DOM.
Code: Alles auswählen
def main():
root = etree.fromstring(source)
get_data_node = root.find('.//{http://MyNS:8080/TestService}getData')
for child in get_data_node:
print child.tag, child.text
Verfasst: Dienstag 4. September 2007, 11:46
von TwistedMetal
Erstmal Vielen Dank für den Code. Ich habe die beiden ausgeführt aber . . .
Wenn ich den folgenden Code ausgeführt habe:
BlackJack hat geschrieben:
Code: Alles auswählen
def main():
osf_namespace_uri = 'http://MyNS:8080/TestService'
doc_node = parseString(xml_in)
get_data_node = doc_node.getElementsByTagNameNS(osf_namespace_uri, 'osf:getData')[0]
for child in (node for node in get_data_node.childNodes
if node.nodeType == node.ELEMENT_NODE):
print child.nodeName, child.firstChild.nodeValue
bekomme ich:
Code: Alles auswählen
Exception happened during processing of request from ('127.0.0.1', 39656)
Traceback (most recent call last):
File "/usr/lib/python2.5/SocketServer.py", line 463, in process_request_thread
self.finish_request(request, client_address)
File "/usr/lib/python2.5/SocketServer.py", line 254, in finish_request
self.RequestHandlerClass(request, client_address, self)
File "osfarm.py", line 1032, in __init__
BaseHTTPServer.BaseHTTPRequestHandler.__init__(self, *params)
File "/usr/lib/python2.5/SocketServer.py", line 521, in __init__
self.handle()
File "/usr/lib/python2.5/BaseHTTPServer.py", line 316, in handle
self.handle_one_request()
File "/usr/lib/python2.5/BaseHTTPServer.py", line 310, in handle_one_request
method()
File "osfarm.py", line 1069, in do_POST
get_data_node = doc_node.getElementsByTagNameNS(osf_namespace_uri, 'osf:getData')[0]
IndexError: list index out of range
und wenn ich ihn ausgeführt habe:
BlackJack hat geschrieben:
Code: Alles auswählen
def main():
root = etree.fromstring(source)
get_data_node = root.find('.//{http://MyNS:8080/TestService}getData')
for child in get_data_node:
print child.tag, child.text
bekomme ich:
Code: Alles auswählen
Exception happened during processing of request from ('127.0.0.1', 57679)
Traceback (most recent call last):
File "/usr/lib/python2.5/SocketServer.py", line 463, in process_request_thread
self.finish_request(request, client_address)
File "/usr/lib/python2.5/SocketServer.py", line 254, in finish_request
self.RequestHandlerClass(request, client_address, self)
File "osfarm.py", line 1032, in __init__
BaseHTTPServer.BaseHTTPRequestHandler.__init__(self, *params)
File "/usr/lib/python2.5/SocketServer.py", line 521, in __init__
self.handle()
File "/usr/lib/python2.5/BaseHTTPServer.py", line 316, in handle
self.handle_one_request()
File "/usr/lib/python2.5/BaseHTTPServer.py", line 310, in handle_one_request
method()
File "osfarm.py", line 1069, in do_POST
for child in get_data_node:
TypeError: 'NoneType' object is not iterable
Verfasst: Dienstag 4. September 2007, 11:56
von BlackJack
Beim ersten: Es gibt kein 'osf:getData', das heisst nur 'getData'. Den XML-Namensraum hat man ja schon als erstes Argument angegeben.
Beim zweiten scheint das `find` nichts gefunden zu haben. Warum auch immer. Bei mir funktioniert's. Kann es sein, dass Du die URI des XML-Namensraums verändert hast?
Verfasst: Dienstag 4. September 2007, 12:13
von TwistedMetal
BlackJack hat geschrieben: Kann es sein, dass Du die URI des XML-Namensraums verändert hast?
Genau das war der Fehler. Jetzt funktioniert alles endlich mal richtig. Vielen vilen Dank für die große Hilfe

Verfasst: Dienstag 4. September 2007, 13:48
von TwistedMetal
Gerade habe ich eine Anpassung an den Code gemacht. Wollte alles in eine Array speichern aber das geht wieder nicht
Code: Alles auswählen
root = etree.fromstring(xml_in)
get_data_node = root.find('.//{http://MyNS:8080/OSFarmWebService}getImage')
for child in get_data_node:
args[i] = child.text
i=i+1 #i++ geht auch nicht
Kann man arrays in python nicht so benutzen wie ich benutzt habe?
Der Fehler ist:
Code: Alles auswählen
Exception happened during processing of request from ('127.0.0.1', 48674)
Traceback (most recent call last):
File "/usr/lib/python2.5/SocketServer.py", line 463, in process_request_thread
self.finish_request(request, client_address)
File "/usr/lib/python2.5/SocketServer.py", line 254, in finish_request
self.RequestHandlerClass(request, client_address, self)
File "osfarm.py", line 1030, in __init__
BaseHTTPServer.BaseHTTPRequestHandler.__init__(self, *params)
File "/usr/lib/python2.5/SocketServer.py", line 521, in __init__
self.handle()
File "/usr/lib/python2.5/BaseHTTPServer.py", line 316, in handle
self.handle_one_request()
File "/usr/lib/python2.5/BaseHTTPServer.py", line 310, in handle_one_request
method()
File "osfarm.py", line 1068, in do_POST
args[i] = child.text
IndexError: list assignment index out of range
Verfasst: Dienstag 4. September 2007, 14:18
von BlackJack
`args` ist eine Liste und die hat eine Länge. Man kann nur an eine existierenden Index etwas zuweisen. Du willst Elemente an die Liste anhängen, dafür gibt es die `append()`-Methode.
In diesem Fall kann man sich die ``for``-Schleife sparen bzw. in eine "list comprehension" stecken um die Liste zu erzeugen:
Verfasst: Dienstag 4. September 2007, 14:27
von TwistedMetal
Wow Cool. Irgendwie finde ich Python ganz intressant

Verfasst: Dienstag 4. September 2007, 18:39
von Leonidas
Was ich jetzt irgendwie übersehen habe: warum nicht einfach eine bestehende SOAP-Library nutzen?