2010-10-06 10 views
8

Sto cercando di ottenere un lettore da recuperare da un XML rotto. L'utilizzo dell'opzione libxml2.XML_PARSE_RECOVER con DOM api (libxml2.readDoc) funziona e recupera dai problemi di entità.python libxml2 reader e XML_PARSE_RECOVER

Tuttavia, l'utilizzo dell'opzione con l'API del lettore (che è essenziale a causa delle dimensioni dei documenti che stiamo analizzando) non funziona. E 'appena si blocca in un ciclo perpetuo (con reader.Read() restituisce -1):

codice di esempio (con piccolo esempio):

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() 

Tutte le idee come recuperare correttamente?

+0

Sì: 'while ret == 1:'. Vedi http://xmlsoft.org/xmlreader.html. –

risposta

1

Non sono molto sicuro dello stato corrente dei collegamenti libxml2. Anche il sito libxml2 suggerisce di utilizzare lxml. Per analizzare questo albero e ignorare il & è bello e pulito 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()) 

Il parsers page nella documentazione lxml va in ulteriori dettagli sulla configurazione di un parser e scorrere il contenuto.

Edit:

Se si vuole analizzare un documento in modo incrementale la classe xmlparser può essere utilizzato come bene dal momento che è una sottoclasse di _FeedParser:

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

Purtroppo ho esaminato anche lxml, ma il tuo suggerimento sopra usa l'API DOM, a causa della dimensione dei documenti che non è un'opzione. L'API lxml iterparse non supporta il ripristino. – bee

+0

Se si sta tentando di analizzare solo in modo incrementale, cercare nell'interfaccia _FeedParser per lxml, modificherò il campione sopra con il suo utilizzo. Non sono stato in grado di trovare un metodo iterativo per l'analisi che produce elementi mentre vengono analizzati. http://codespeak.net/lxml/api/lxml.etree._FeedParser-class.html – dcolish

+0

Grazie per tutti gli sforzi. Tecnicamente ciò di cui abbiamo bisogno è il parsing incrementale e il pull degli elementi basato sugli eventi con recupero. Vergogna lxml non soddisfa questi requisiti. – bee

0

Non è il xml rotto in qualche coerente modo? Non c'è qualche schema che potresti seguire per riparare il tuo xml prima di analizzare?

Ad esempio: se l'errore è causato solo da e commerciali senza caratteri di escape e non si utilizza CDATA o le istruzioni di elaborazione, è possibile ripararlo con un'espressione regolare.

MODIFICA: Quindi dare un'occhiata a sgmllib nella libreria standard python. BeautifulSoup lo usa, quindi può essere utile nel tuo caso. (BeatifulSoup offre solo la rappresentazione ad albero, non gli eventi).

+0

Negli esempi che ho guardato ogni singola fonte ha rotto xml e tutto in modi diversi! Altri errori comuni sono l'inviluppo di tag di apertura e chiusura non corrispondenti. Sarebbe difficile lavorare su ognuno di essi, almeno in modo affidabile. Per finire, riparare i sorgenti non è un'opzione - dobbiamo supportarli come ha fatto il precedente provider! – bee

0

Considerare l'utilizzo di xml.sax. Quando mi viene presentato un XML veramente malformato che può avere una pletora di problemi diversi, prova a dividere il problema in piccoli pezzi.

Hai accennato al fatto che hai un file XML molto grande, beh probabilmente ha molti record da elaborare in serie. E ogni record (ad esempio <item>...</item> ha un tag di inizio e di fine, presumibilmente - questi saranno volere i punti di ripristino

In xml.sax you provide the reader, the handler, and the input sources A peggiorare un singolo record non saranno recuperabili con questa tecnica E 'un po' di più messa a punto, ma in modo incrementale l'analisi di un... errato feed un record alla volta la registrazione dei record errati è probabilmente la migliore che si possa fare.

Nei registri assicurarsi di darti informazioni sufficienti per ricostruire il record originale in modo da poter aggiungere ulteriore codice di ripristino per tutti i casi che senza dubbio dovrai gestire (ad es. creare un badrecords_ today's date .xml in modo da poterlo rielaborare manualmente)

Buona fortuna.

0

Oppure, è possibile utilizzare BeautifulSoup. Fa un bel lavoro recuperando ML rotta.

+0

BeautifulSoup è basato su DOM quindi carica l'intero documento in memoria, che non soddisfa i requisiti. È anche piuttosto lento per qualcosa di considerevole, a parte le esigenze di memoria. – bee