如何在minidom中禁用'输出转义

1 投票
3 回答
4122 浏览
提问于 2025-04-16 10:05

我正在尝试使用 xml.dom.minidom 从头开始构建一个 XML 文档。一切进展顺利,直到我想在文本节点中加入一个 ®(注册商标)符号。我的目标是,当我最终执行 print mydoc.toxml() 时,这个特定的节点能够真正包含一个 ® 符号。

我首先尝试了:

import xml.dom.minidom as mdom
data = '®'

结果出现了一个很明显的错误:

  File "C:\src\python\HTMLGen\test2.py", line 3
SyntaxError: Non-ASCII character '\xae' in file C:\src\python\HTMLGen\test2.py on line 3, but no encoding declared; see http://www.python.or
g/peps/pep-0263.html for details

当然,我也尝试过通过在脚本开头加上编码声明,把 Python 脚本的编码改成 'utf-8',但这并没有解决问题。

所以我想到了:

import xml.dom.minidom as mdom

data = '®'  #Both accepted xml encodings for registered trademark
data = '®'

text = mdom.Text()
text.data = data

print data
print text.toxml()

但是因为当我打印 text.toxml() 时,& 符号被转义了,所以我得到了这样的输出:

®
®

我的问题是,有没有办法强制输出中的 & 符号不被转义,这样我就可以让我的特殊字符引用在 XML 文档中保留下来?

基本上,对于这个节点,我希望 print text.toxml() 能够愉快地输出 ®®

编辑 1

顺便说一下,如果 minidom 确实没有这个功能,我很乐意使用你推荐的其他模块。

编辑 2

正如 Hugh 建议的那样,我尝试使用 data = u'®'(同时在数据中使用 # -*- coding: utf-8 -*- 的 Python 源代码标签)。这在某种程度上有帮助,因为它确实使 ® 符号被输出到我的 XML 中。但这并不是我想要的结果。正如你们可能已经猜到的(也许我应该早些说明),这个 XML 文档实际上是一个 HTML 页面,需要在浏览器中正常工作。所以在文档中有 ® 符号会导致浏览器出现乱码(具体来说是 ®!)。

我还尝试了:

data = unichr(174)
text.data = data.encode('ascii','xmlcharrefreplace')
print text.toxml()

但当然,这又导致了最初的问题,所有的结果都是 & 符号被 .toxml() 转义了。

我理想的情况是有某种方法可以转义 & 符号,这样 XML 打印功能就不会为我“转义”它(换句话说,实现我最初的目标,让 ®® 出现在文档中)。

看起来我很快就得求助于正则表达式了!

编辑 2a

或者也许不是。似乎正确设置我的 HTML 元信息 <META http-equiv="Content-Type" Content="text/html; charset=UTF-8"> 可能会有所帮助,但我还不确定这如何与 XML 结构相结合……

3 个回答

2

默认的反转义:

from xml.sax.saxutils import unescape
unescape("&lt; &amp; &gt;")

结果是,

'< & >'

还有,更多的反转义:

unescape("&apos; &quot;", {"&apos;": "'", "&quot;": '"'})

详细信息请查看这里, https://wiki.python.org/moin/EscapingXml

2

如果我理解得没错,你真正想要的是能够从一个 unicode 对象(比如 u'®'u'\u00ae')创建一个文本节点,然后让 toxml() 输出的unicode字符以实体的形式编码(比如 &#174;)。不过,从 minidom.py 的源代码来看,minidom 似乎不支持除了 &"<> 这几个特殊情况之外的实体编码。

你还问到了其他可能有帮助的模块。其实有几个可选的模块,但 ElementTree(xml.etree)似乎可以进行合适的编码。例如,如果你从 Doug Hellmann 的这篇博客 中拿到第一个例子,然后把:

child_with_tail.text = 'This child has regular text.'

... 替换为:

child_with_tail.text = u'This child has regular text \u00ae.'

... 然后运行这个脚本,你应该能看到输出中包含:

This child has regular text&#174;.

你也可以在这个例子中使用 lxml 的 ElementTree 实现,只需把导入语句替换为:

from lxml.etree import Element, SubElement, Comment, tostring

更新:John Machin 提供的另一个 答案 采用了一个不错的方法,就是对 minidom 的 toxml() 输出运行 .encode('ascii', 'xmlcharrefreplace'),这样可以把任何非 ASCII 字符转换成它们对应的 XML 数字字符引用。

3

这里有两种可行的选择,一种是用转义字符 &#174;,另一种是不使用转义字符。其实不太明显为什么需要用转义字符……因为用转义字符的方式占用6个字节,而不使用转义字符的方式只占用2或3个字节,对于非中文、日文、韩文的字符来说。

import xml.dom.minidom as mdom
text = mdom.Text()
# Start with unicode
text.data = u'\xae'

f = open('reg1.html', 'w')
f.write("header saying the file is ascii")
uxml = text.toxml()
bxml = uxml.encode('ascii', 'xmlcharrefreplace')
f.write(bxml)
f.close()

f = open('reg2.html', 'w')
f.write("header saying the file is UTF-8")
xml = text.toxml(encoding='UTF-8')
f.write(xml)
f.close()

撰写回答