如何使用Python Element Tree 生成XML, UTF-8 with BOM?

How to generate XML, UTF-8 with BOM using Python Element Tree?

为 ASP.NET 生成资源 XML 文件,第三方工具需要 BOM(迁移到新版本的工具时)。同时,它需要像 <?xml version='1.0' encoding='utf-8'?>.

这样的 XML prolog

问题是在使用 ElementTree 命令时...

tree.write(lang_resx_fpath, encoding='utf-8')

生成的文件不包含 BOM。使用命令时...

tree.write(lang_resx_fpath, encoding='utf-8-sig')

结果确实包含BOM;但是,XML 序言包含 encoding='utf-8-sig'.

我应该如何生成包含 BOM 和 encoding='utf-8' 的文件?

更新:

我已经通过读取、替换和再次写入文件来解决这个问题,就像这样...

with open(lang_resx_fpath, 'r', encoding='utf-8-sig') as f:
    content = f.read()

content = content.replace("encoding='utf-8-sig'", "encoding='utf-8'")

with open(lang_resx_fpath, 'w', encoding='utf-8-sig') as f:
    f.write(content)

无论如何,有没有更清洁的解决方案?

更新: 我创建了 https://bugs.python.org/issue46598, and I have also written the fix (https://github.com/python/cpython/pull/31043).

查看 ElementTree.write 的源代码表明 prolog 在那里被硬编码 (https://github.com/python/cpython/blob/main/Lib/xml/etree/ElementTree.py or permalink https://github.com/python/cpython/blob/ee0ac328d38a86f7907598c94cb88a97635b32f8/Lib/xml/etree/ElementTree.py)。因此,使用 ET 的内部结构可能是唯一的选择(除了 monkey-pathing 模块),以编写所需的序言并将 BOM 保留在文件中:

import xml.etree.ElementTree as ET
qnames, namespaces = ET._namespaces(tree._root, None)
with open(lang_resx_fpath,'w',encoding='utf-8-sig') as f:
    f.write("<?xml version='1.0' encoding='utf-8'?>\n"     )
    ET._serialize_xml(f.write,
                        tree._root, qnames, namespaces,
                       short_empty_elements=False)

可能它并不比您的解决方案更优雅(甚至可能更不优雅)。唯一的优点是它不需要两次写入文件,除了一些巨大的 XML 文件之外,这将是次要的好处。