使用Python替换XML文档中的数字字符引用

时间:2010-10-08 21:50:25

标签: python xml

我正在努力解决以下问题:我有一个包含以下标记的XML字符串,我想使用cElementTree将其转换为有效的XML文档:

<tag>#55296;#57136;#55296;#57149;#55296;#57139;#55296;#57136;#55296;#57151;#55296;
#57154;#55296;#57136;</tag>

但每个#符号前面都有&amp;符号,因此输出看起来像:

这是一个unicode字符串,编码为UTF-8。我想丢弃这些数字字符引用,因为它们在有效的XML文档中不是合法的XML(参见Parser error using Perl XML::DOM module, "reference to invalid character number"

我尝试过不同的正则表达式来匹配这些数字字符引用。例如,我尝试了以下(Python)正则表达式:

RE_NUMERIC_CHARACTER = re.compile('&#[\d{1,5}]+;')

这在普通的python会话中有效,但是一旦我在我的代码中使用相同的正则表达式,它就不起作用,大概是因为那些数字字符已被解释(并显示为方框或问号)。

我也尝试过来自http://effbot.org/zone/re-sub.htm的unescape函数,但这也不起作用。

因此:如何使用Python中的正则表达式匹配这些数字字符引用并创建有效的XML文档?

1 个答案:

答案 0 :(得分:4)

Eurgh。你有代理(D800-DFFF范围内的UTF-16代码单元),有些傻瓜单独编码不正确,而不是单个字符使用一对代码单元。用应该的样子来代替这个混乱是理想的:

<tag>&#66352;&#66365;&#66355;&#66352;&#66367;&#66370;&#66352;</tag>

或者,就像文字字符一样有效(如果你有一个可以显示哥特字母的字体):

<tag></tag>

通常,最好在解析的文本节点上执行此类替换操作,以避免在其他位置(例如注释或PI)中弄乱非字符引用序列。当然,在这种情况下,这是不可能的,因为这根本不是真正的XML。您可以尝试使用粗糙的正则表达式来修复它,但最好找出无效输入的来源,并在负责人修复之前对其负责。

>>> def lenient_deccharref(m):
...    return unichr(int(m.group(1)))
...
>>> tag= '<tag>&#55296;&#57136;&#55296;&#57149;&#55296;&#57139;&#55296;&#57136;&#55296;&#57151;&#55296;&#57154;&#55296;&#57136;</tag>'
>>> re.sub('&#(\d+);', lenient_deccharref, tag).encode('utf-8')
'<tag>\xf0\x90\x8c\xb0\xf0\x90\x8c\xbd\xf0\x90\x8c\xb3\xf0\x90\x8c\xb0\xf0\x90\x8c\xbf\xf0\x90\x8d\x82\xf0\x90\x8c\xb0</tag>'

这是的正确UTF-8编码。 utf-8编解码器允许您编码一系列代理以纠正UTF-8,即使在广泛的Unicode平台上,代理不应该首先出现在字符串中。

>>> _.decode('utf-8')
u'<tag>\U00010330\U0001033d\U00010333\U00010330\U0001033f\U00010342\U00010330</tag>'
相关问题