我正在尝试将一些代码移植到Python 3,它将 xml.sax.make_parser
函数创建的解析器作为 xml.dom.minidom.parseString
的第二个参数传递给解析XML文档 .
在Python 3中,解析器似乎无法将XML文档解析为 bytes
,但在解析之前我无法知道XML文档的编码 . 展示:
import xml.sax
import xml.dom.minidom
def try_parse(input, parser=None):
try:
xml.dom.minidom.parseString(input, parser)
except Exception as ex:
print(ex)
else:
print("OK")
euro = u"\u20AC" # U+20AC EURO SIGN
xml_utf8 = b"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
xml_cp1252 = b"<?xml version=\"1.0\" encoding=\"windows-1252\"?>"
test_cases = [
b"<a>" + euro.encode("utf-8") + b"</a>",
u"<a>" + euro + u"</a>",
xml_utf8 + b"<a>" + euro.encode("utf-8") + b"</a>",
xml_cp1252 + b"<a>" + euro.encode("cp1252") + b"</a>",
]
for i, case in enumerate(test_cases, 1):
print("%d: %r" % (i, case))
try_parse(case)
try_parse(case, xml.sax.make_parser())
Python 2:
1: '<a>\xe2\x82\xac</a>'
OK
OK
2: u'<a>\u20ac</a>'
'ascii' codec can't encode character u'\u20ac' in position 3: ordinal not in range(128)
'ascii' codec can't encode character u'\u20ac' in position 3: ordinal not in range(128)
3: '<?xml version="1.0" encoding="utf-8"?><a>\xe2\x82\xac</a>'
OK
OK
4: '<?xml version="1.0" encoding="windows-1252"?><a>\x80</a>'
OK
OK
Python 3:
1: b'<a>\xe2\x82\xac</a>'
OK
initial_value must be str or None, not bytes
2: '<a>€</a>'
OK
OK
3: b'<?xml version="1.0" encoding="utf-8"?><a>\xe2\x82\xac</a>'
OK
initial_value must be str or None, not bytes
4: b'<?xml version="1.0" encoding="windows-1252"?><a>\x80</a>'
OK
initial_value must be str or None, not bytes
如您所见,默认解析器能够正常处理 bytes
,但我需要SAX解析器来处理参数实体 . 有没有解决这个问题的方法(除了在解析之前尝试猜测 bytes
的编码)?
1 回答
我好像找到了问题的原因 .
xml.dom.minidom.parseString
调用xml.dom.pulldom.parseString
如果提供了解析器(通过_do_pulldom_parse
),然后尝试构造StringIO
以在解析时保存XML文档 . 换掉StringIO
为BytesIO
解决了问题,所以我想我会使用以下方法作为解决方法: