我写了一个小函数,它使用 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 之外的其他解析器或 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]
。