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:

Code: Alles auswählen

<xml.dom.minidom.Document instance at 0xa03748c>
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

Code: Alles auswählen

print doc_node.documentElement.tagName == "class"
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 :wink:

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
Joghurt hat geschrieben:<offtopic>
Jeder, der sich mit SOAP beschäftigen muss, wird das hier nachvollziehen können:
http://wanderingbarque.com/nonintersect ... or-simple/
</offtopic>
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

Code: Alles auswählen

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

Code: Alles auswählen

    args = [child.text for child in get_data_node]

Verfasst: Dienstag 4. September 2007, 14:27
von TwistedMetal
Wow Cool. Irgendwie finde ich Python ganz intressant :D

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