5

我写了一个小函数,它使用 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]

4

2 回答 2

6

&#0;不在XML 规范定义的合法字符范围内。唉,我的 Python 技能还很初级,所以我帮不上什么忙。

于 2010-06-14T16:13:38.100 回答
4

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

如果您必须接受这些文件,您可以对它们进行预处理以&#0变成其他东西。例如,选择@作为转义字符,将“@”转为“@@”,将“ &#0;”转为“@0”。

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

于 2010-06-14T16:23:54.523 回答