Python ElementTree 生成格式不正确的 XML 文件,其中包含特殊字符'x0b'



我用ElementTree生成特殊字符为'\x0b'的xml,然后使用minidom来解析它。它将抛出not well-formed错误。

import xml.etree.ElementTree as ET
from xml.dom import minidom
root = ET.Element('root')
root.text='x0b'
xml = ET.tostring(root, 'UTF-8')
print(xml)
pretty_tree = minidom.parseString(xml)

生成的 XML:<root>x0b</root>

错误

Traceback (most recent call last):
File "testXml.py", line 7, in <module>
pretty_tree = minidom.parseString(xml)
File "/usr/local/Cellar/python/3.7.7/Frameworks/Python.framework/Versions/3.7/lib/python3.7/xml/dom/minidom.py", line 1968, in parseString
return expatbuilder.parseString(string)
File "/usr/local/Cellar/python/3.7.7/Frameworks/Python.framework/Versions/3.7/lib/python3.7/xml/dom/expatbuilder.py", line 925, in parseString
return builder.parseString(string)
File "/usr/local/Cellar/python/3.7.7/Frameworks/Python.framework/Versions/3.7/lib/python3.7/xml/dom/expatbuilder.py", line 223, in parseString
parser.Parse(string, True)
xml.parsers.expat.ExpatError: not well-formed (invalid token): line 1, column 6

此行为过去曾作为错误提出,并解决为"无法修复"。

元素树模块的作者评论道

对于ET来说,[这种行为]在很大程度上是故意的。 验证每个提供的数据 单个应用程序会扼杀所有应用程序的性能,即使只有一个 少数人会尝试序列化无法表示的数据 在 XML 中。

结束语(由 lxml 的维护者,他也是 Python 核心开发人员(包括以下观察结果:

例如,lxml验证用户输入,但那是因为它无论如何都必须处理它,并且直接在输入上完成它(并且在C代码中非常有效(。另一方面,ET对允许用户做的事情相当宽松,并且不会对用户输入进行太多处理。它甚至在处理过程中允许无效树,并且只期望树在请求序列化时可序列化。

我认为这是一种公平的行为,因为大多数用户输入都可以,并且不需要承受验证所有输入的性能损失。例如,在文本中很少找到空字符,我认为让用户自己处理可能发生的少数情况是合理的。

最后,真正关心正确输出的用户应该在序列化后对其运行某种架构验证,因为这不仅可以检测数据问题,还可以检测结构和逻辑问题(例如缺少或空属性(,特别是针对其目标数据格式。在某些情况下,它甚至可能检测到由于服务器机器中的旧非ECC RAM而导致的随机数据损坏。:)

因此,总而言之,ET.tostring将生成格式不正确的xml,这是设计使然。 如有必要,可以使用ET.fromstring或其他解析器解析输出以检查其格式是否正确。 或者,可以使用 lxml 代替 ElementTree。

x0b是一个受XML限制的字符。 在这个问题的答案中,对有效字符和受限字符有很好的描述。

作为我自己的解决方法,我编写了一个帮助程序方法来在保存到 XML 模型之前清理受限制的字符:

def clean(str):
return re.sub(r'[^u0009u000Au000Du0020-uD7FFuE000-uFFFDu10000-u10FFF]+', '', str)

最新更新