2009-07-16 75 views
9

我用elementtree.parse()函數解析了一些XML。它的工作原理除了一些utf-8字符(128字節以上的單字節字符)。我看到默認的解析器是基於expat的XMLTreeBuilder。ElementTree替代XML解析器來緩解UTF-8的災難?

有沒有我可以使用,可能不太嚴格,並允許UTF-8字符替代分析器?

這是我與默認解析器得到的錯誤:

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

造成這種情況的字符是一個單字節X92(十六進制)。我不確定這甚至是一個有效的utf-8字符。但它會是不錯的處理,因爲大多數文本編輯器顯示此爲:我

編輯:人物的背景是:canít,在這裏我想這應該是一個奇特的apostraphe,但在十六進制編輯器,則相同的序列爲:63 61 6E 92 74

回答

15

我會從開始的問題:「有沒有辦法,我可以使用另一種解析器可能不太嚴格,並允許UTF-8字符?」

所有XML解析器都將接受以UTF-8編碼的數據。實際上,UTF-8是默認編碼。

一個XML文件可能有這樣的聲明開始:

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

或像這樣: <?xml version="1.0"?> 或沒有申報在所有...在每種情況下的解析器將文檔使用UTF解碼-8。

但是,您的數據不是以UTF-8編碼的......它可能是Windows-1252又名cp1252。

如果編碼不是UTF-8,則創建者應該包含一個聲明(或者接收者可以預先設置一個)或者接收者可以將數據轉碼爲UTF-8。以下展示什麼可行,什麼不行:

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

字節0x92永遠不會成爲UTF-8字符的第一個字節的第一個字節。但是,它可以作爲後續字節有效。有關有效字節序列的表,請參閱this UTF-8 guide

你能不能給我們帶來什麼字節周邊0x92的想法? XML聲明是否包含字符編碼?

4

它看起來像你有CP1252文本。如果是的話,它應該在文件的頂部指定,如:

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

這確實與ElementTree的工作。

如果你自己創建這些文件,不要把它們寫在這個編碼。將它們保存爲UTF-8,並盡你所能幫助殺死過時的文本編碼。

如果您收到沒有編碼規範CP1252的數據,你肯定知道,它總是將是CP1252,你可以就其發送到解析器之前轉換爲UTF-8:

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

不是歐洲人,我們絕對是在美國。我沒有這樣做,我保證:) – Kekoa 2009-07-16 21:37:35

1

啊。這是「不可」,顯然,在許多Windows代碼頁中0x92是一個撇號。你的編輯器會假設它是一個Mac文件。 ;)

如果它是一次性的,固定的文件是做正確的事。但是,當你需要導入其他人的XML時,幾乎總是有很多事情不符合規定的編碼。我發現最好的解決方案是使用錯誤設置'xmlcharrefreplace'進行解碼,並且在嚴重情況下進行自定義字符替換,以修復該特定客戶最常見的問題。

我也給你推薦LXML如在Python XML庫,但在這裏,這不是問題。