Domanda

Io sono l'analisi di alcuni XML con la funzione elementtree.parse (). Funziona, ad eccezione di alcuni caratteri UTF-8 (a byte singolo sopra 128). Vedo che il parser di default è XMLTreeBuilder che si basa su expat.

C'è un parser alternativa che posso usare che possono essere meno rigorosi e consentire caratteri UTF-8?

Questo è l'errore che sto ottenendo con il parser di default:

ExpatError: not well-formed (invalid token): line 311, column 190

Il carattere causando questo è un singolo byte x92 (in esadecimale). Io non sono certo questo è ancora un carattere valido UTF-8. Ma sarebbe bello per gestire la cosa perché la maggior parte degli editor di testo visualizzano questo come: i

Modifica : Il contesto del personaggio è: Canit, dove suppongo che si suppone che sia un apostraphe di fantasia, ma nel editor esadecimale, la stessa sequenza è: 63 61 6E 92 74

È stato utile?

Soluzione

Comincerò dalla domanda: "C'è un parser alternativa che posso usare che possono essere meno rigorosi e consentire caratteri UTF-8?"

Tutti i parser XML accetteranno dati codificati in UTF-8. Infatti, UTF-8 è la codifica predefinita.

Un documento XML può iniziare con una dichiarazione come questa:

`<?xml version="1.0" encoding="UTF-8"?>`

o come questo:     <?xml version="1.0"?> o non hanno una dichiarazione a tutti ... in ogni caso il parser decodificare il documento utilizzando UTF-8.

Tuttavia i dati non siano codificati in UTF-8 ... è probabilmente di Windows-1252 aka CP1252.

Se la codifica non è UTF-8, allora o il creatore dovrebbe includere una dichiarazione (o il destinatario può anteporre uno) o il destinatario può convertire i dati in UTF-8. Di seguito mette in mostra ciò che funziona e ciò che non lo fa:

>>> import xml.etree.ElementTree as ET
>>> from StringIO import StringIO as sio

>>> raw_text = '<root>can\x92t</root>' # text encoded in cp1252, no XML declaration

>>> t = ET.parse(sio(raw_text))
[tracebacks omitted]
xml.parsers.expat.ExpatError: not well-formed (invalid token): line 1, column 9
# parser is expecting UTF-8

>>> t = ET.parse(sio('<?xml version="1.0" encoding="UTF-8"?>' + raw_text))
xml.parsers.expat.ExpatError: not well-formed (invalid token): line 1, column 47
# parser is expecting UTF-8 again

>>> t = ET.parse(sio('<?xml version="1.0" encoding="cp1252"?>' + raw_text))
>>> t.getroot().text
u'can\u2019t'
# parser was told to expect cp1252; it works

>>> import unicodedata
>>> unicodedata.name(u'\u2019')
'RIGHT SINGLE QUOTATION MARK'
# not quite an apostrophe, but better than an exception

>>> fixed_text = raw_text.decode('cp1252').encode('utf8')
# alternative: we transcode the data to UTF-8

>>> t = ET.parse(sio(fixed_text))
>>> t.getroot().text
u'can\u2019t'
# UTF-8 is the default; no declaration needed

Altri suggerimenti

Sembra che tu hai testo CP1252. Se è così, si dovrebbe specificare nella parte superiore del file, ad esempio:.

<?xml version="1.0" encoding="CP1252" ?>

Questo funziona con ElementTree.

Se si sta creando questi file da soli, non li scrivono in questa codifica. salvarli come UTF-8 e fare la vostra parte per aiutare a uccidere le codifiche di testo obsoleti.

Se stai ricevendo i dati CP1252 senza specifica codifica, e si sa per certo che è sempre sarà CP1252, si può solo convertirlo in UTF-8 prima di inviarlo al parser:

s.decode("CP1252").encode("UTF-8")

Byte 0x92 non è mai valida come primo byte di caratteri UTF-8. Può essere valide un successivo byte, tuttavia. Vedere questo UTF-8 Guida per un tavolo di sequenze di byte validi.

Ci può dare un'idea di che cosa byte circondano 0x92? Ha la dichiarazione XML includono una codifica dei caratteri?

Ah. Questo è il "CAN NOT", ovviamente, e in effetti, 0x92 è un apostrofo in molte pagine di codice di Windows. Il tuo editore si assume, invece, che si tratta di un file di Mac. ;)

Se si tratta di un one-off, che fissa il file è la cosa giusta da fare. Ma quasi sempre quando si ha bisogno di importare altri popoli XML c'è un sacco di cose che semplicemente non sono d'accordo con la codifica indicato. Ho trovato che la soluzione migliore è quella di decodificare con errore di impostazione 'xmlcharrefreplace', e nei casi più gravi fare il vostro sostituzione di un carattere proprio personalizzato che consente di risolvere i problemi più comuni di quel particolare cliente.

Sarò anche consiglio lxml come libreria XML in Python, ma non è il problema qui.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top