我使用 django,在我看来,我需要以 XML 格式发送一个请求,其中包含一些 unicode 字符,该请求使用 post 方法从 html 页面接收。我尝试了这些(请注意,我将该输入保存在 fname 变量中):
xml = r"""my XML code with unicode {0} """.format(fname)
和
fname = u"%s".encode('utf8') % (fname)
xml = r"""my XML code with unicode {0} """.format(fname)
和
fname = fname.encode('ascii', 'ignore').decode('ascii')
xml = r"""my XML code with unicode {0} """.format(fname)
每次我收到此错误时:
'ascii' codec can't encode characters in position 0-3: ordinal not in range(128)
您可以使用以下代码重现错误:
>>> "{0}".format(u"U0001F384"*4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: ordinal not in range(128)
要修复此特定错误,只需使用 Unicode 格式字符串:
>>> u"{0}".format(u"U0001F384"*4)
u'U0001f384U0001f384U0001f384U0001f384'
您可以使用xml.etree.ElementTree
模块来构建xml文档,而不是字符串格式.xml这是一种复杂的格式;很容易出错。 ElementTree
还会将 Unicode 字符串正确序列化为字节,以确保 xml 声明中的字符编码与文档中使用的实际编码一致。
xml = r"""my XML code with unicode {0} """.format(fname)
.format
方法始终生成与输入格式字符串相同的输出字符串类型。如果你的格式字符串是一个字节字符串r"""..."""
所以如果fname
是一个Unicode字符串,Python试图强制它成为一个字节字符串。如果frame
包含默认编码 (ASCII) 中不存在的字符,则 bang。
请注意,这与旧的字符串格式化运算符 %
不同,当格式字符串或使用的任何参数为 Unicode 时,它尝试提升为 Unicode 字符串,只要my XML code
与 ASCII 兼容,在这种情况下就可以工作。这是将使用%
的代码转换为.format()
时出现的常见问题。
这应该可以正常工作:
xml = ur"""my XML code with unicode {0} """.format(fname)
但是,输出将是一个 Unicode 字符串,因此无论您接下来做什么都需要处理它(例如,如果您将其写入字节流/文件,您可能希望.encode('utf-8')
整个事情)。或者,就地对其进行编码以获取字节字符串:
xml = r"""my XML code with unicode {0} """.format(fname.encode('utf-8'))
请注意,上面是:
fname = u"%s".encode('utf8') % (fname)
不起作用,因为您将格式字符串编码为字节,而不是fname
参数。这与只说fname = '%s' % fname
相同,这实际上是fname = fname
。
我用这段代码解决了这个问题:
fname = fname.encode('ascii', 'xmlcharrefreplace')
这闻起来很臭。对于输入hello ☃
,您现在正在生成hello ☃
而不是正常的输出hello ☃
。
如果☃
和☃
在输出中看起来相同,那么您可能正在执行以下操作:
xml = '<element>{0}</element>'.format(some_text)
对于 XML 特殊字符(如 &
和 <
)会损坏。当你生成XML时,你应该注意转义特殊字符(&<>"'
,&
,<
等),否则你的输出充其量会因为这些字符而中断; 在最坏的情况下,当some_text
包含用户输入时,您会遇到一个 XML 注入漏洞,该漏洞可能会以安全老化的方式破坏系统的逻辑。
正如 J F Sebastian 所说 (+1),最好使用现有的已知良好的 XML 序列化库(如 etree
),而不是尝试自己创建。
你可以做这样的事情:
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
但它是一个丑陋的黑客,只适用于Python 2.7。
或
fname.encode('GB18030').decode('utf-8')
它将绕过错误,但可能仍然看起来很混乱。如果您要发布到 html 文件,则使字符集 utf-8
我用这段代码解决了这个问题:
fname = fname.encode('ascii', 'xmlcharrefreplace')
xml = r"""my XML code with unicode {0} """.format(fname)
谢谢你的帮助。
更新:你可以用这个删除或替换像>和<这样的特殊字符(感谢@bobince注意这一点):>
fname = fname.replace("<", "")
fname = fname.replace(">", "")
fname = fname.replace("&", "")