Python 过滤lxml中无效unicode字符的中心方法?

Python 过滤lxml中无效unicode字符的中心方法?,python,xml,unicode,lxml,invalid-characters,Python,Xml,Unicode,Lxml,Invalid Characters,这是XML文档中不允许的常识。我知道过滤掉这些字符的解决方案(比如,) 按照“不要重复自己”原则,我更愿意在一个中心点实施其中一个解决方案——现在,我必须在将任何潜在的不安全文本输入到lxml之前对其进行清理。是否有办法实现这一点,例如通过子类化lxml过滤器类、捕获一些异常或设置配置开关 编辑:希望能澄清一下这个问题,这里有一个示例代码: from lxml import etree root = etree.Element("root") root.text = u'\uffff' ro

这是XML文档中不允许的常识。我知道过滤掉这些字符的解决方案(比如,)

按照“不要重复自己”原则,我更愿意在一个中心点实施其中一个解决方案——现在,我必须在将任何潜在的不安全文本输入到
lxml
之前对其进行清理。是否有办法实现这一点,例如通过子类化
lxml
过滤器类、捕获一些异常或设置配置开关


编辑:希望能澄清一下这个问题,这里有一个示例代码:

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")
执行此命令将得到结果

<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
￿�
回溯(最近一次呼叫最后一次):
文件“[…]”,第9行,在
root.text+=u'\u0002'
文件“lxml.etree.pyx”,第953行,在lxml.etree.\u Element.text.\uuu\u set\uuuu中(src/lxml/lxml.etree.c:44956)
文件“apihelpers.pxi”,第677行,在lxml.etree.\u setNodeText(src/lxml/lxml.etree.c:20273)中
文件“apihelpers.pxi”,第1395行,位于lxml.etree.\u utf8(src/lxml/lxml.etree.c:26485)
ValueError:所有字符串都必须与XML兼容:Unicode或ASCII,无空字节或控制字符
如您所见,2字节会引发异常,但lxml很高兴地转义了另外两个超出范围的字符。真正的问题是

s = "<root>&#65535;&#55296;</root>"
root = etree.fromstring(s)
s=“￿;�;”
root=etree.fromstring
也会引发异常。在我看来,这种行为有点令人不安,特别是因为它会生成无效的XML文档


事实证明,这可能是一个2对3的问题。对于python3.4,上面的代码抛出异常

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
回溯(最近一次呼叫最后一次):
文件“[…]”,第5行,在
root.text+=u'\ud800'
文件“lxml.etree.pyx”,第953行,在lxml.etree.\u Element.text.\uuu\u set\uuuu中(src/lxml/lxml.etree.c:44971)
文件“apihelpers.pxi”,第677行,在lxml.etree.\u setNodeText(src/lxml/lxml.etree.c:20273)中
文件“apihelpers.pxi”,第1387行,在lxml.etree.\u utf8(src/lxml/lxml.etree.c:26380)中
UnicodeEncodeError:“utf-8”编解码器无法对位置1中的字符“\ud800”进行编码:不允许使用代理

剩下的唯一问题是
\uffff
字符,
lxml
仍然乐于接受该字符。

只需在lxml中解析字符串之前对其进行过滤即可:

我用你的代码试过了;这似乎是可行的,请记住,您需要更改要点以导入re和sys


也许这应该在lxml本身中修复。你有没有向lxml项目提交bug?@oefe我没有。但这似乎是
libxml
(其中lxml只是一个包装器)的问题,因为PHP的
DOMDocument
(另一个包装器)也会转义超出范围的字符,并且在以后加载此类文档时出现问题,因此,最好在那里填写错误报告。作为临时解决方案,您可以使用lxml
从lxml.html.soupparser从string导入提供的
soupparser
,它将毫无问题地吃掉“&&65535;&&55296;”。它基于libxml2的解析器
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"))