2010-10-06 8 views
8

Ich versuche, einen Leser von gebrochenem XML zu erholen. Die Verwendung der Option libxml2.XML_PARSE_RECOVER mit der DOM-API (libxml2.readDoc) funktioniert und es wird von Entitätsproblemen wiederhergestellt.Python libxml2 Leser und XML_PARSE_RECOVER

Die Verwendung der Option mit der Reader-API (die aufgrund der Größe der zu analysierenden Dokumente erforderlich ist) funktioniert jedoch nicht.

Beispielcode (mit kleinen Beispiel):

import cStringIO 
import libxml2 

DOC = "<a>some broken & xml</a>" 

reader = libxml2.readerForDoc(DOC, "urn:bogus", None, libxml2.XML_PARSE_RECOVER | libxml2.XML_PARSE_NOERROR) 

ret = reader.Read() 
while ret: 
    print 'ret: %d' % ret 
    print "node name: ", reader.Name(), reader.NodeType() 
    ret = reader.Read() 

Irgendwelche Ideen, wie ich erholen richtig es nur wird in einer ewigen Schleife (mit reader.Read() liefert -1) stecken?

+0

Ja: 'während ret == 1:'. Siehe http://xmlsoft.org/xmlreader.html. –

Antwort

1

Ich bin nicht sicher über den aktuellen Status der libxml2-Bindungen. Selbst die libxml2-Seite schlägt stattdessen die Verwendung von lxml vor. Um diesen Baum zu analysieren und die & ignorieren ist schön und sauber in lxml:

from cStringIO import StringIO 
from lxml import etree 

DOC = "<a>some broken & xml</a>" 

reader = etree.XMLParser(recover=True) 
tree = etree.parse(StringIO(DOC), reader) 
print etree.tostring(tree.getroot()) 

Die parsers page in dem lxml docs geht mehr ins Detail über einen Parser Einrichten und Iteration über den Inhalt.

Edit:

Wenn Sie ein Dokument inkrementell die XmlParser Klasse analysieren wollen, können auch verwendet werden, da es sich um eine Unterklasse von _FeedParser ist:

DOC = "<a>some broken & xml</a>" 
reader = etree.XMLParser(recover=True) 

for data in StringIO(DOC).read(): 
    reader.feed(data) 

tree = reader.close() 
print etree.tostring(tree) 
+0

Leider habe ich auch in lxml gesucht, aber Ihr Vorschlag oben verwendet die DOM-API, aufgrund der Größe der Dokumente, die keine Option ist. Die lxml iterparse-API unterstützt keine Wiederherstellung. – bee

+0

Wenn Sie nur inkrementell zu analysieren versuchen, schauen Sie in die _FeedParser-Schnittstelle für lxml, ich werde das obige Beispiel mit seiner Verwendung bearbeiten. Ich konnte keine iterative Methode zum Parsen finden, die Elemente bei der Analyse liefert. http://codespeak.net/lxml/api/lxml.etree._FeedParser-class.html – dcolish

+0

Vielen Dank für Ihre Bemühungen. Was wir technisch benötigen, ist sowohl inkrementelles Parsen als auch ereignisgesteuertes Ziehen von Elementen mit Wiederherstellung. Shame lxml erfüllt diese Anforderungen nicht. – bee

0

Ist nicht die xml in einigen konsistent gebrochen Weg? Gibt es nicht ein Muster, das Sie befolgen könnten, um Ihr XML vor der Analyse zu reparieren?

Zum Beispiel - wenn der Fehler nur durch Unescaped Ampersands verursacht wird und Sie nicht CDATA oder Verarbeitungsanweisungen verwenden, kann es mit einem Regexp repariert werden.

EDIT: Dann werfen Sie einen Blick auf sgmllib in Python-Standard-Bibliothek. BeautifulSoup verwendet es, damit es in Ihrem Fall nützlich sein kann. (BeatifulSoup selbst bietet nur die Baumdarstellung, nicht die Ereignisse).

+0

In den Beispielen, die ich mir angesehen habe, hat jede einzelne Quelle xml und alles auf verschiedene Arten gebrochen! Andere häufige Fehler sind das Verbergen von öffnenden und schließenden Tags, die nicht übereinstimmen. Es wäre schwierig, jeden einzelnen zuverlässig zu umgehen. Obendrein ist es keine Option, die Quellen zu reparieren - wir müssen sie unterstützen, wie der vorherige Anbieter es tat! – bee

0

Verwenden Sie xml.sax. Wenn ich wirklich falsch formatiertes XML präsentiere, das eine Vielzahl von verschiedenen Problemen haben kann, versuche das Problem in kleine Teile zu teilen.

Sie haben erwähnt, dass Sie eine sehr große XML-Datei haben, also wahrscheinlich viele Datensätze, die Sie seriell verarbeiten. Und jeder Datensatz (zB <item>...</item> hat einen Start- und End-Tag, vermutlich - diese Wiederherstellungspunkte werden

In xml.sax you provide the reader, the handler, and the input sources Bei schlechter eine einzelne Datensätze mit dieser Technik nicht wiederherstellbar sein wird, seine ein wenig mehr Setup, aber schrittweise ein Parsen... falsch formatiert Feed ein Rekord auf einmal die schlechten Aufzeichnungen protokollieren ist wahrscheinlich das Beste, was Sie tun können

In den Protokollen stellen Sie sicher, sich genügend Informationen zu geben, um den ursprünglichen Datensatz neu zu erstellen, damit Sie zusätzlichen Wiederherstellungscode für alle Fälle hinzufügen können Sie müssen zweifellos damit umgehen (zB erstellen Sie eine badrecords_ today's date .xml, so dass Sie manuell erneut verarbeiten können).

Viel Glück.

0

Oder Sie könnten BeautifulSoup verwenden. Es macht einen schönen Job, gebrochene ML zu erholen.

+0

BeautifulSoup basiert auf DOM, lädt also das gesamte Dokument in den Speicher, was nicht den Anforderungen entspricht. Es ist auch ziemlich langsam für etwas größere, Speicheranforderungen beiseite. – bee