Parse SOAP xml fehler

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
TwistedMetal
User
Beiträge: 8
Registriert: Dienstag 4. September 2007, 09:09

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 :)
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.
TwistedMetal
User
Beiträge: 8
Registriert: Dienstag 4. September 2007, 09:09

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:
Joghurt
User
Beiträge: 877
Registriert: Dienstag 15. Februar 2005, 15:07

<offtopic>
Jeder, der sich mit SOAP beschäftigen muss, wird das hier nachvollziehen können:
http://wanderingbarque.com/nonintersect ... or-simple/
</offtopic>
TwistedMetal
User
Beiträge: 8
Registriert: Dienstag 4. September 2007, 09:09

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 :?
TwistedMetal
User
Beiträge: 8
Registriert: Dienstag 4. September 2007, 09:09

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 ??
Zuletzt geändert von TwistedMetal am Dienstag 4. September 2007, 11:23, insgesamt 1-mal geändert.
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
TwistedMetal
User
Beiträge: 8
Registriert: Dienstag 4. September 2007, 09:09

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
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?
TwistedMetal
User
Beiträge: 8
Registriert: Dienstag 4. September 2007, 09:09

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 :)
TwistedMetal
User
Beiträge: 8
Registriert: Dienstag 4. September 2007, 09:09

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
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]
TwistedMetal
User
Beiträge: 8
Registriert: Dienstag 4. September 2007, 09:09

Wow Cool. Irgendwie finde ich Python ganz intressant :D
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Was ich jetzt irgendwie übersehen habe: warum nicht einfach eine bestehende SOAP-Library nutzen?
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Antworten