2014-04-20 16 views
9

Kiến thức phổ biến là certain character ranges không được phép trong tài liệu XML. Tôi biết các giải pháp để lọc các ký tự đó (như [1], [2]).Cách trung tâm để lọc các ký tự unicode không hợp lệ trong lxml?

Nguyên tắc Don't Repeat Yourself, tôi muốn thực hiện một trong các giải pháp này ở một điểm chính - ngay bây giờ, tôi phải khử trùng bất kỳ văn bản có thể không an toàn nào trước khi được cấp cho lxml. Có cách nào để đạt được điều này không, ví dụ: bằng cách phân lớp lớp lọc lxml, bắt một số ngoại lệ hoặc cài đặt công tắc cấu hình?


Edit: Để hy vọng làm rõ câu hỏi này một chút, đây là một mẫu mã:

from lxml import etree 

root = etree.Element("root") 
root.text = u'\uffff' 
root.text += u'\ud800' 

print(etree.tostring(root)) 

root.text += '\x02'.decode("utf-8") 

Thực thi này mang lại cho kết quả

<root>&#65535;&#55296;</root> 

Traceback (most recent call last): 
    File "[…]", line 9, in <module> 
    root.text += u'\u0002' 
    File "lxml.etree.pyx", line 953, in lxml.etree._Element.text.__set__ (src/lxml/lxml.etree.c:44956) 
    File "apihelpers.pxi", line 677, in lxml.etree._setNodeText (src/lxml/lxml.etree.c:20273) 
    File "apihelpers.pxi", line 1395, in lxml.etree._utf8 (src/lxml/lxml.etree.c:26485) 
ValueError: All strings must be XML compatible: Unicode or ASCII, no NULL bytes or control characters 

Như bạn thấy, một ngoại lệ được ném cho 2 byte, nhưng lxml vui vẻ thoát khỏi hai ký tự khác ngoài phạm vi ký tự. Vấn đề thực sự là

s = "<root>&#65535;&#55296;</root>" 
root = etree.fromstring(s) 

cũng ném ngoại lệ. Hành vi này là một chút đáng lo ngại trong quan điểm của tôi, đặc biệt là bởi vì nó tạo ra các tài liệu XML không hợp lệ.


Chỉ ra rằng đây có thể là vấn đề 2 so với 3. Với python3.4, các mã trên ném ngoại lệ

Traceback (most recent call last): 
    File "[…]", line 5, in <module> 
    root.text += u'\ud800' 
    File "lxml.etree.pyx", line 953, in lxml.etree._Element.text.__set__ (src/lxml/lxml.etree.c:44971) 
    File "apihelpers.pxi", line 677, in lxml.etree._setNodeText (src/lxml/lxml.etree.c:20273) 
    File "apihelpers.pxi", line 1387, in lxml.etree._utf8 (src/lxml/lxml.etree.c:26380) 
UnicodeEncodeError: 'utf-8' codec can't encode character '\ud800' in position 1: surrogates not allowed 

Vấn đề duy nhất còn lại là \uffff nhân vật, mà lxml vẫn vui vẻ chấp nhận.

+2

Có lẽ điều này phải được sửa trong chính lxml. Bạn đã gửi lỗi cho dự án lxml chưa? – oefe

+1

@oefe tôi đã không làm vậy. Nhưng có vẻ như đây là vấn đề của 'libxml' (mà lxml chỉ là một trình bao bọc) vì' DOMDocument' của PHP (một trình bao bọc khác) cũng thoát khỏi các ký tự nằm ngoài phạm vi und có vấn đề khi tải các tài liệu đó sau đó, vì vậy có thể một lỗi báo cáo tốt hơn nên được điền ở đó. –

+1

là giải pháp tạm thời bạn có thể sử dụng 'soupparser' được cung cấp bởi lxml ' từ lxml.html.soupparser nhập từ chuỗi' và nó sẽ ăn " & # 65535; & # 55296;" mà không có vấn đề gì. nó dựa trên trình phân tích cú pháp của libxml2 – Urban48

Trả lời

1

Chỉ lọc chuỗi trước khi bạn phân tích cú pháp trong LXML: cleaning invalid characters from XML (gist by lawlesst).

Tôi đã thử với mã của bạn; có vẻ như hoạt động, lưu thực tế là bạn cần phải thay đổi ý chính để nhập lạisys!

from lxml import etree 
from cleaner import invalid_xml_remove 

root = etree.Element("root") 
root.text = u'\uffff' 
root.text += u'\ud800' 

print(etree.tostring(root)) 

root.text += invalid_xml_remove('\x02'.decode("utf-8")) 
Các vấn đề liên quan