Python + Expat: 实体出错

时间:2010-06-14 16:09:34

标签: python xml parsing elementtree expat-parser

我编写了一个小函数,它使用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>&#0;</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列

&#0;实体是非法XML吗?无论是否,我要解析的文件都包含它,我需要一些方法来解析它们。对于另一个解析器而不是Expat的任何建议,或Expat的设置,这将允许我这样做吗?


更新:我刚才发现了BeautifulSoup,这是一个标记汤解析器,如下面的答案评论中所述,为了好玩,我回到了这个问题,并尝试在ElementTree前使用它作为XML清理器,但它尽职地将&#0;转换为一个无效的空字节。 : - )

cleaned_s = StringIO(
  BeautifulStoneSoup('<test><null>&#0;</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 个答案:

答案 0 :(得分:6)

&#0;不在XML规范定义的legal character range中。唉,我的Python技能非常简陋,所以我在那里帮助不大。

答案 1 :(得分:4)

&#0;不是有效的XML字符。理想情况下,您可以让文件的创建者更改其进程,以便文件不会像这样无效。

如果您必须接受这些文件,则可以对其进行预处理,以便将&#0转换为其他内容。例如,选择@作为转义字符,将“@”转换为“@@”,将“&#0;”转换为“@ 0”。

然后,当您从解析器获取文本数据时,您可以反转映射。这只是一个例子,你可以发明任何你想要的转义语法。