2009-07-16 23 views
9

Tôi đang phân tích cú pháp một số XML với hàm elementtree.parse(). Nó hoạt động, ngoại trừ một số ký tự utf-8 (ký tự byte đơn trên 128). Tôi thấy rằng trình phân tích cú pháp mặc định là XMLTreeBuilder dựa trên người nước ngoài.Trình phân tích cú pháp XML thay thế cho ElementTree để giảm bớt tai họa UTF-8?

Có một trình phân tích cú pháp thay thế mà tôi có thể sử dụng có thể ít nghiêm ngặt hơn và cho phép các ký tự utf-8 không?

Đây là lỗi tôi nhận được với phân tích cú pháp mặc định:

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

Nhân vật gây ra điều này là một x92 byte duy nhất (trong hex). Tôi không chắc chắn điều này thậm chí là một ký tự utf-8 hợp lệ. Nhưng nó sẽ được tốt đẹp để xử lý nó bởi vì hầu hết các biên tập viên văn bản hiển thị này như: í

EDIT: bối cảnh của ký tự là: không thể, nơi tôi cho rằng nó được coi là một apostraphe ưa thích, nhưng trong hex trình chỉnh sửa, cùng trình tự đó là: 63 61 6E 92 74

Trả lời

15

Tôi sẽ bắt đầu từ câu hỏi: "Có một trình phân tích cú pháp thay thế mà tôi có thể sử dụng có thể ít nghiêm ngặt hơn và cho phép các ký tự utf-8 không?"

Tất cả các trình phân tích cú pháp XML sẽ chấp nhận dữ liệu được mã hóa bằng UTF-8. Trong thực tế, UTF-8 là mã hóa mặc định.

Một tài liệu XML có thể bắt đầu với một bản tuyên bố như thế này:

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

hay như thế này: <?xml version="1.0"?> hay không có một tuyên bố ở tất cả ... đối với từng trường hợp phân tích cú pháp sẽ giải mã các tài liệu sử dụng UTF -số 8.

Tuy nhiên, dữ liệu của bạn KHÔNG được mã hóa bằng UTF-8 ... có thể là Windows-1252 hay còn gọi là cp1252.

Nếu mã hóa không phải là UTF-8, thì người tạo nên bao gồm một tuyên bố (hoặc người nhận có thể thêm một) hoặc người nhận có thể chuyển mã dữ liệu sang UTF-8. Sau đây giới thiệu những gì hiệu quả và những gì không:

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

Byte 0x92 không bao giờ hợp lệ là byte đầu tiên của ký tự UTF-8. Tuy nhiên, nó có thể hợp lệ như một byte tiếp theo. Xem this UTF-8 guide để biết bảng các chuỗi byte hợp lệ.

Bạn có thể cho chúng tôi biết ý tưởng về byte nào xung quanh 0x92 không? Tuyên bố XML có bao gồm mã hóa ký tự không?

4

Dường như bạn có văn bản CP1252. Nếu vậy, nó phải được chỉ định ở đầu tệp, ví dụ:

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

Điều này làm việc với ElementTree.

Nếu bạn tự mình tạo các tệp này, không viết chúng trong mã hóa này. Lưu chúng dưới dạng UTF-8 và làm một phần của bạn để giúp tiêu diệt các mã hóa văn bản lỗi thời.

Nếu bạn đang nhận dữ liệu CP1252 không có đặc điểm kỹ thuật mã hóa, và bạn biết chắc chắn rằng nó luôn luôn sẽ CP1252, bạn chỉ có thể chuyển đổi nó sang UTF-8 trước khi gửi nó vào phân tích cú pháp:

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

Không phải châu Âu, chúng tôi chắc chắn ở Hoa Kỳ. Tôi không làm điều đó, tôi hứa :) – Kekoa

+0

Câu hỏi của bạn bị cắt xén: bạn nói rằng văn bản là "không thể", đó là một chữ cái nhỏ tôi có dấu chấm (u2019). Tôi đối phó với đủ ngoại ngữ không xác định một cách thường xuyên mà tôi giải thích bằng văn bản. Vui lòng sửa câu hỏi. Câu trả lời là như nhau; chỉ cần thay thế CP852 cho CP1252. Nhân tiện, 0x92 trong CP1252 không phải là dấu nháy đơn, đó là một ‘báo giá’ đúng. Tôi có lẽ không nên ngạc nhiên rằng một số phần mềm bị hỏng đủ để có được * dấu nháy đơn * sai. (Không phải lỗi của bạn - lỗi của bất kỳ phần mềm nào đã xuất ra chuỗi đó.) –

+0

@Glenn Maynard: (1) Việc sao chép văn bản không phải ASCII bởi một OP thường bị cắt xén. Những gì bạn thấy không phải lúc nào cũng là những gì họ có. the_raw_bytes.repr() là bạn của họ và của bạn. "Apostraphe" của ông là một đầu mối quan trọng (2) "bức thư nhỏ tôi với một cấp tính (u2019)": huh? Theo tiêu chuẩn Unicode, U + 2019 là MARK CHUYÊN NGHIỆP QUẢNG CÁO khi được mã hóa trong cp1252 là 0x92 (3) Các nhà sản xuất phần mềm bị cáo buộc phải đọc chuẩn Unicode về U + 2019: "đây là ký tự được ưu tiên sử dụng cho dấu nháy đơn ". (4) cp852? 0x92 -> NHỎ LETTER L (ell not I eye) VỚI ACUTE –

1

Ah. Đó là "không thể", rõ ràng, và thực sự, 0x92 là một dấu nháy đơn trong nhiều trang mã Windows. Trình soạn thảo của bạn giả định rằng đó là một tệp Mac. ;)

Nếu đó là một lần, việc sửa tệp là điều đúng để thực hiện. Nhưng hầu như luôn luôn khi bạn cần nhập XML của người khác, có rất nhiều thứ đơn giản là không đồng ý với mã hóa đã nêu. Tôi đã tìm thấy giải pháp tốt nhất là giải mã với cài đặt lỗi 'xmlcharrefreplace' và trong trường hợp nghiêm trọng, hãy thay thế ký tự tùy chỉnh của riêng bạn để khắc phục các sự cố thường gặp nhất cho khách hàng cụ thể đó.

Tôi cũng sẽ đề xuất lxml làm thư viện XML bằng Python, nhưng đó không phải là vấn đề ở đây.

Các vấn đề liên quan