Frage

Ich bin Parsen einige XML mit dem elementtree.parse () Funktion. Es funktioniert, mit Ausnahme einiger utf-8-Zeichen (Single-Byte-Zeichen über 128). Ich sehe, dass die Standard-Parser ist XMLTreeBuilder, die auf Expat basiert.

Gibt es einen Alternativen Parser, die ich, dass möglicherweise weniger strengen verwenden kann und erlaubt utf-8-Zeichen?

Das ist der Fehler, den ich bin mit dem Standard-Parser bekommen:

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

Der Charakter dieses verursacht, ist ein einziges Byte x92 (in hex). Ich bin nicht sicher, dies ist auch ein gültiges utf-8-Zeichen. Aber es wäre schön, es zu handhaben, weil die meisten Texteditoren dieser Anzeige als: I

Bearbeiten : Der Kontext des Zeichens ist: Canit, wo ich nehme an, es soll eine Phantasie apostraphe sein, aber im Hex-Editor, dass gleiche Sequenz ist: 63 61 6E 92 74

War es hilfreich?

Lösung

Ich werde von der Frage beginnen: „Gibt es einen alternativen Parser, dass ich das auch sein mag kann weniger streng und erlauben utf-8-Zeichen?“

Alle XML-Parser werden die Daten in UTF-8 codiert akzeptieren. In der Tat, UTF-8 ist die Standardcodierung.

Ein XML-Dokument mit einer Erklärung wie folgt beginnen kann:

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

oder wie folgt aus:     <?xml version="1.0"?> oder keine Erklärung hat überhaupt ... in jedem Fall der Parser das Dokument mit UTF-8 wird dekodieren.

Allerdings Ihre Daten nicht in UTF-8 kodiert ist ... es ist wahrscheinlich von Windows-1252 aka cp1252.

Wenn die Codierung nicht UTF-8 ist, dann ist entweder der Schöpfer sollte eine Erklärung (oder der Empfänger kann einen prepend) umfasst oder der Empfänger kann die Daten in UTF-8 umcodieren. Im Folgenden zeigt, was funktioniert und was nicht:

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

Andere Tipps

Es sieht aus wie Sie CP1252 Text haben. Wenn ja, sollte es am Anfang der Datei angegeben werden, zB:.

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

Das mit ElementTree funktioniert.

Wenn Sie diese Dateien sind selbst erstellen, nicht schreiben sie in dieser Codierung. Speichern Sie diese als UTF-8 und Ihren Teil veraltete Textcodierungen töten zu helfen.

Wenn Sie CP1252 Daten ohne Codierung Spezifikation sind zu empfangen und Sie wissen sicher, dass es immer CP1252 sein würde, können Sie einfach konvertieren es in UTF-8, bevor es an den Parser zu senden:

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

Byte 0x92 ist nie gültig als erster Byte von UTF-8-Zeichen. Es kann als ein nachfolgendes Byte jedoch gültig sein. Siehe dieser UTF-8-Führer für einen Tisch gültiger Byte-Sequenzen.

Könnten Sie geben uns eine Vorstellung von dem, was Bytes 0x92 sind rund um? Enthält die XML-Deklaration enthält eine Zeichencodierung?

Ah. Das ist „KANN NICHT“, natürlich, und in der Tat, 0x92 ist ein Apostroph in vielen Windows-Codepages. Ihr Herausgeber übernimmt stattdessen, dass es eine Mac-Datei. ;)

Wenn es ein einmaliger, die Datei Fixierung ist das Richtige zu tun. Aber fast immer, wenn Sie andere Völker importieren müssen XML gibt es eine Menge Dinge, die einfach nicht mit der angegebenen Codierung übereinstimmen. Ich habe festgestellt, dass die beste Lösung mit dem Fehler zu dekodieren ist ‚xmlcharrefreplace‘ Einstellung, und in schweren Fällen Ihre eigenen Charakter Ersatz zu tun, die die häufigsten Probleme für diesen bestimmten Kunden fixiert.

Ich werde auch lxml als XML-Bibliothek in Python empfehlen, aber das ist nicht das Problem hier.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top