2009-09-22 9 views
7

Ich habe ein XML-Dokument in über einen Sockel kommen, die ich brauche zu analysieren und darauf zu reagieren on the fly (dh einen Teilbaum Parsing). Was ich möchte ist eine nicht blockierende Methode, so dass ich andere Dinge tun kann, während ich darauf warte, dass mehr Daten reinkommen (ohne Threading).nicht blockierenden Methode zum Parsen (Streaming) XML in Python

So etwas wie iterparse ideal wäre, wenn es Iterieren beendet, wenn der Lesepuffer leer ist, zB:

context = iterparse(imaginary_socket_file_wrapper) 
while 1: 
    for event, elem in context: 
     process_elem(elem) 
    # iteration of context finishes when socket has no more data 
    do_other_stuff() 
    time.sleep(0.1) 

Ich denke, SAX wäre auch eine Option sein, aber iterparse scheint nur einfacher für meine Bedürfnisse. Irgendwelche Ideen?

Update:

Mit Gewinde ist in Ordnung, aber stellt ein Maß an Komplexität, die ich zu umgehen hoffte auf. Ich dachte, dass nicht blockierende Aufrufe eine gute Möglichkeit wären, dies zu tun, aber ich stelle fest, dass dies die Komplexität der Analyse des XML erhöht.

Antwort

8

Eintauchen in die Itersparse-Quelle lieferte die Lösung für mich.Hier ist ein einfaches Beispiel für den Aufbau eine XML-Struktur auf der Fliege und Verarbeitungselementen nach ihrer Nähe tags:

import xml.etree.ElementTree as etree 

parser = etree.XMLTreeBuilder() 

def end_tag_event(tag): 
    node = self.parser._end(tag) 
    print node 

parser._parser.EndElementHandler = end_tag_event 

def data_received(data): 
    parser.feed(data) 

In meinem Fall landete ich es Daten aus verdrillt Fütterung, aber es sollte auch mit einem nicht blockierenden Socket arbeiten .

+0

Ich kann diese Antwort nicht genug reichen – donopj2

+0

Danke Peter. Dank Ihrer Antwort habe ich endlich eine andere Antwort auf meine Frage gefunden. Siehe meine ausführlichere Antwort: https://stackoverflow.com/a/44414167/938111 – olibre

1

Wenn Sie keine Threads verwenden, können Sie eine Ereignisschleife verwenden und nicht blockierende Sockets abfragen.

asyncore ist das Standard-Bibliothek-Modul für solche Sachen. Twisted ist die async-Bibliothek für Python, aber komplex und wahrscheinlich ein bisschen Schwergewicht für Ihre Bedürfnisse.

Alternativ ist multiprocessing die nicht-Thread Thread Alternative, aber ich nehme an, Sie nicht 2.6 ausgeführt werden.

Eine oder andere Weise, ich denke, du wirst Threads verwenden müssen, zusätzliche Prozesse oder eine ebenso komplexe async Magie weben.

+0

asyncore sieht gut aus, aber ich würde immer noch eine Möglichkeit der Parsing der XML, die die Komplexität nicht überschreitet einfach iparsparsed in einen anderen Thread (sagen wir) –

+0

Right. War mir nicht sicher warum die Fäden raus waren. Das Eventlets sieht in diesem Fall gut aus, aber nicht wesentlich einfacher als ein Thread. So wie ich es sehe, wenn Sie gleichzeitig/async/threaded Verhalten wollen, müssen Sie den Preis für diese Komplexität auf die eine oder andere Weise bezahlen. Eine XML-Bibliothek (oder fast jede andere Bibliothek) wird nicht mit dieser Art von Funktionalität ausgestattet sein, weil sie auf einer anderen Abstraktionsebene besser ausgeführt wurde. – wbg

4

Ich denke, es gibt zwei Komponenten dazu, die nicht-blockierende Netzwerk-I/O und einen stromorientierten XML-Parser.

Für Ersteres müssen Sie ein nicht blockierendes Netzwerkframework auswählen oder eine eigene Lösung dafür erstellen. Twisted würde sicherlich funktionieren, aber ich persönlich finde die Umkehrung der Kontrollrahmen schwierig, mein Gehirn herum zu wickeln. Sie müssten wahrscheinlich in Ihren Rückrufen eine Menge Status verfolgen, um den Parser zu füttern. Aus diesem Grund tendiere ich dazu, Eventlet ein bisschen einfacher zu programmieren zu finden, und ich denke, dass es in dieser Situation gut passen würde.

Im Wesentlichen erlaubt es Ihnen, Ihren Code zu schreiben als ob Sie eine blockierende Socket-Aufruf wurden unter Verwendung (eines gewöhnlichen Schleife oder einen Generator mit oder was auch immer Sie mögen), mit der Ausnahme, dass Sie es in einen separaten Koroutine laichen können (ein " greenlet "), die automatisch eine kooperative Ausbeute erzielt, wenn I/O-Operationen blockiert werden, wodurch andere Coroutinen ausgeführt werden können.

Dies macht jeden stromorientierte Parser trivial erneut verwendet wird, da der Code wie ein gewöhnlicher blockierenden Anruf aufgebaut ist. Es bedeutet auch, dass viele Bibliotheken, die nicht direkt mit Sockets oder anderen I/O arbeiten (wie der Parser zum Beispiel), nicht speziell modifiziert werden müssen, um nicht blockierend zu sein: Wenn sie blockieren, liefert Eventlet die Coroutine.

Zugegeben, Eventlet ist leicht magisch, aber ich finde es hat eine viel leichtere Lernkurve als Twisted, und führt zu einfacher Code, weil Sie nicht Ihre Logik "nach außen" auf das Framework passen müssen.

+0

Twisted ist in der Tat ziemlich schwer zu verstehen, aber sobald du 'Defredred' verstehst, ist es erstaunlich mächtig. Ich habe kurz auf eventlet geschaut, und es basiert auf Threads, die das OP ausgeschlossen hat. Ich habe nicht gesagt, warum Threads keine Option waren. Wenn es um Komplexität geht, sieht Eventlet voller Gewinn aus. – wbg

+0

Eigentlich Eventlet erfordert keine Threads, aber es ist orthogonal zu und kompatibel mit ihnen. Es verwendet eine C-Erweiterung namens "greenlet", die kooperative Korotinen implementiert, die man sich als verallgemeinerte Version von Pythons Generatoren vorstellen kann: Ein Greenlet kann die Kontrolle übernehmen und später dort fortgesetzt werden, wo es aufgehört hat. Eventlet verwendet diese Funktion, um automatisch ein beliebiges Greenlet zu erzeugen, wenn eine E/A-Operation ausgeführt wird, die blockiert und später wieder aufgenommen wird, wenn die E/A abgeschlossen ist. Tatsächlich benutzt es einen Twisted-like Reaktor unter der Haube, aber um Greenlets zu planen, anstatt es direkt auszusetzen. – edarc

+0

Twisted scheint sich auf HTML und HTTP zu konzentrieren. Gibt es Beispiele für die Verwendung von Twisted mit einfachen XML- und TCP-Sockets? –