代码之家  ›  专栏  ›  技术社区  ›  clacke

python+expat:实体出错

  •  5
  • clacke  · 技术社区  · 15 年前

    我编写了一个小函数,它使用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解析,我可以使用漂亮的soup本身及其非常简单的节点寻址风格。 parsed_tree.test.elem1.contents[0] .

    2 回复  |  直到 15 年前
        1
  •  6
  •   McDowell rahul gupta    15 年前

    &#0; 不在 legal character range 由XML规范定义的。哎呀,我的Python技术还很初级,所以我在这方面没什么帮助。

        2
  •  4
  •   Ned Batchelder    15 年前

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

    如果你必须接受这些文件,你可以预先处理它们 &#0 到别的地方去。例如,选择@作为转义符,将“@”转换为“@@”,然后 &α0; “入”“0”。

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