【问题标题】:Replace numeric character references in XML document using Python使用 Python 替换 XML 文档中的数字字符引用
【发布时间】:2010-10-08 21:50:24
【问题描述】:

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

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

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

这是一个 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 文档?

【问题讨论】:

  • 它已经是一个有效的文件。这些字符是有效的 Unicode 字符。输出看起来像垃圾,因为您可能没有以控制台允许的编码进行打印。什么操作系统?您的控制台的 Unicode 编码是什么?
  • 我使用的是 Windows 7,但我根本没有使用控制台,当我将字符串提供给 cElementTree.XML() 时会引发错误
  • @S.Lott: &amp;#55296; 不是有效的字符引用,因为它引用了代理代码单元 (0xD800)。
  • @DrDee:“因此输出看起来像......”和“当我输入字符串时抛出错误”对我来说没有任何意义。您遇到什么确切错误?请复制粘贴。
  • @S.Lott:我正在从文件 XML 中读取,我正在尝试从该文件构造 XML DOM(使用 cElementTree),该文件包含上述标签,我得到的错误消息是: SyntaxError:引用无效字符号。因此,我试图去掉那些数字字符,但还没有成功。我明天将使用@bobince 解决方案

标签: python xml


【解决方案1】:

哎呀。您有代理(D800-DFFF 范围内的 UTF-16 代码单元),有些傻瓜错误地单独编码,而不是为单个字符使用一对代码单元。用它应该的样子来替换这个烂摊子是理想的:

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

或者,同样有效,在文字字符中(如果你有一种可以显示哥特字母的字体):

<tag>???????</tag>

通常,最好在解析的文本节点上执行这样的替换操作,以避免在其他地方(如 cmets 或 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>'

【讨论】:

  • 好的,我需要复制这个。原始代码确实包含 & 字符,但我把它省略了,所以它会显示在 Stackflow 上。
  • 由于粘贴错误,我最初在示例中省略了&amp;,但它确实有效。如果您将&amp;#...; 放在代码块中(反引号或四个空格),SO 不会尝试将其视为字符引用。
  • -1 关于整个问题:“原始代码确实包含 & 字符”。如果您不能发布实际代码,则需要天才来推断您做错了什么。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-13
  • 2012-12-24
  • 1970-01-01
  • 1970-01-01
  • 2022-10-23
  • 1970-01-01
相关资源
最近更新 更多