使用 UTF-8 进行输出时,Python ElementTree 不会转换不间断空格

标签 python xml encoding elementtree

我正在尝试使用 Python 的 ElementTree 解析、操作和输出 HTML:

import sys
from cStringIO  import StringIO
from xml.etree  import ElementTree as ET
from htmlentitydefs import entitydefs

source = StringIO("""<html>
<body>
<p>Less than &lt;</p>
<p>Non-breaking space &nbsp;</p>
</body>
</html>""")

parser = ET.XMLParser()
parser.parser.UseForeignDTD(True)
parser.entity.update(entitydefs)
etree = ET.ElementTree()

tree = etree.parse(source, parser=parser)
for p in tree.findall('.//p'):
    print ET.tostring(p, encoding='UTF-8')

当我在 Mac OS X 10.6 上使用 Python 2.7 运行它时,我得到:

<p>Less than &lt;</p>

Traceback (most recent call last):
  File "bar.py", line 20, in <module>
    print ET.tostring(p, encoding='utf-8')
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/xml/etree/ElementTree.py", line 1120, in tostring
    ElementTree(element).write(file, encoding, method=method)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/xml/etree/ElementTree.py", line 815, in write
    serialize(write, self._root, encoding, qnames, namespaces)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/xml/etree/ElementTree.py", line 931, in _serialize_xml
    write(_escape_cdata(text, encoding))
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/xml/etree/ElementTree.py", line 1067, in _escape_cdata
    return text.encode(encoding, "xmlcharrefreplace")
UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 19: ordinal not in range(128)

我认为指定“encoding='UTF-8'”会处理不间断空格字符,但显然它不会。我应该怎么做?

最佳答案

0xA0 是 latin1 字符,不是 unicode 字符,循环中 p.text 的值是 str 而不是 unicode,这意味着为了将它编码为 utf-8,它必须首先由 Python 隐式转换转换为 unicode 字符串(即使用解码)。当它这样做时,它假定为 ascii,因为它没有被告知任何其他信息。 0xa0 不是有效的 ascii 字符,但它是有效的 latin1 字符。

你有 latin1 字符而不是 unicode 字符的原因是因为 entitydefs 是名称到 latin1 编码字符串的映射。您需要可以从 htmlentitydef.name2codepoint 获得的 unicode 代码点

下面的版本应该会为您修复它:

import sys
from cStringIO  import StringIO
from xml.etree  import ElementTree as ET
from htmlentitydefs import name2codepoint

source = StringIO("""<html>
<body>
<p>Less than &lt;</p>
<p>Non-breaking space &nbsp;</p>
</body>
</html>""")

parser = ET.XMLParser()
parser.parser.UseForeignDTD(True)
parser.entity.update((x, unichr(i)) for x, i in name2codepoint.iteritems())
etree = ET.ElementTree()

tree = etree.parse(source, parser=parser)
for p in tree.findall('.//p'):
    print ET.tostring(p, encoding='UTF-8')

关于使用 UTF-8 进行输出时,Python ElementTree 不会转换不间断空格,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10653752/

相关文章:

python - Django 模型在两种情况下都是独一无二的

python - unicode_literals 是做什么用的?

java - 将输入流保存到 ByteArray

python - 未使用mock.patch调用函数

python - 为什么具有相同 key 的相同字符串的 AES 加密密码总是不同的?

GF(2)有限域中的Python乘法逆

python - OpenERP 7 : Adding a button on a product view

c++ - boost 属性树 xml 编写器输出中没有行尾

sql-server - 使用 CDATA 的 SQL Server XML 输出

python - Python中有类似iconv的功能吗?