【问题标题】:Python ElementTree generate not well formed XML file with special character '\x0b'Python ElementTree 使用特殊字符“\x0b”生成格式不正确的 XML 文件
【发布时间】:2020-09-17 16:01:51
【问题描述】:

我使用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

【问题讨论】:

    标签: python xml special-characters non-well-formed


    【解决方案1】:

    此行为过去曾被提出为 bug,并已解决为“无法修复”。

    ElementTree 模块的作者commented

    对于 ET,[这种行为] 非常有目的。验证每个人提供的数据 单个应用程序会降低所有应用程序的性能,即使只有一个 少数人会尝试序列化无法表示的数据 在 XML 中。

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

    这是一个棘手的决定。例如,lxml 验证用户输入,但那是因为它无论如何都必须处理它并且直接在输入上进行处理(并且在 C 代码中非常有效)。另一方面,ET 对允许用户执行的操作相当宽松,并且不会对用户输入进行太多处理。它甚至允许在处理过程中使用无效树,并且只希望树在被请求序列化时是可序列化的。

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

    ...

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

    ...

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

    【讨论】:

    • 感谢您的详细解释。很不幸。很多时候我们使用 XML 作为通用数据序列化格式,我们无法控制底层数据是什么。就我而言,我花了几个小时来解决一个序列化大量用户输入数据(几 MB)的错误。解析器中的错误消息没有告诉我正确的位置。所以我必须进行二进制搜索,直到找到这个问题。这似乎是 XML 规范的一个问题,它对接受的字符集施加了不必要的限制。
    【解决方案2】:

    \x0b 是一个 XML 受限字符。在this question 的答案中对有效和受限字符进行了很好的描述。

    【讨论】:

      【解决方案3】:

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

      def clean(str):
        return re.sub(r'[^\u0009\u000A\u000D\u0020-\uD7FF\uE000-\uFFFD\u10000-\u10FFF]+', '', str)
      

      【讨论】:

        猜你喜欢
        • 2012-07-02
        • 2013-06-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多