Python + Expat: � 实体错误
我写了一个小函数,使用ElementTree和xpath来提取xml文件中某些元素的文本内容:
#!/usr/bin/env python2.5
import doctest
from xml.etree import ElementTree
from StringIO import StringIO
def parse_xml_etree(sin, xpath):
"""
Takes as input a stream containing XML and an XPath expression.
Applies the XPath expression to the XML and returns a generator
yielding the text contents of each element returned.
>>> parse_xml_etree(
... StringIO('<test><elem1>one</elem1><elem2>two</elem2></test>'),
... '//elem1').next()
'one'
>>> parse_xml_etree(
... StringIO('<test><elem1>one</elem1><elem2>two</elem2></test>'),
... '//elem2').next()
'two'
>>> parse_xml_etree(
... StringIO('<test><null>�</null><elem3>three</elem3></test>'),
... '//elem2').next()
'three'
"""
tree = ElementTree.parse(sin)
for element in tree.findall(xpath):
yield element.text
if __name__ == '__main__':
doctest.testmod(verbose=True)
第三个测试失败了,出现了以下错误:
ExpatError: 引用无效字符编号:第1行,第13列
这个�
实体算不算非法的XML呢?不管它是否合法,我想解析的文件里都有这个东西,我需要找到一种方法来解析它。有没有其他的解析器推荐,或者Expat的设置,可以让我做到这一点?
更新:我刚发现了BeautifulSoup,这是一个标签解析器,正如下面回答中的评论所提到的。为了好玩,我回到这个问题,尝试在ElementTree之前用它作为XML清理工具,但它乖乖地把�
转换成了同样无效的空字节。:-)
cleaned_s = StringIO(
BeautifulStoneSoup('<test><null>�</null><elem3>three</elem3></test>',
convertEntities=BeautifulStoneSoup.XML_ENTITIES
).renderContents()
)
tree = ElementTree.parse(cleaned_s)
... 结果是
xml.parsers.expat.ExpatError: not well-formed (invalid token): line 1, column 12
不过在我具体的情况下,我其实并不需要像这样使用XPath解析,我完全可以直接用BeautifulSoup,它的节点地址风格相当简单,比如parsed_tree.test.elem1.contents[0]
。
2 个回答
4
�
不是一个有效的 XML 字符。理想情况下,你应该让文件的创建者修改他们的流程,这样文件就不会变得无效了。
如果你必须接受这些文件,你可以先处理一下,把 �
转换成其他东西。比如,可以选择 @ 作为转义字符,把 "@" 变成 "@@",把 "�
" 变成 "@0"。
然后,当你从解析器获取文本数据时,可以把这个转换再反过来。这只是一个例子,你可以自己发明任何你喜欢的转义语法。
6
�
这个字符不在 XML 规范定义的 合法字符范围 内。可惜,我的 Python 技能还很基础,所以在这方面帮不上忙。