使用(X)HTML实体解析XML

时间:2013-02-07 06:23:58

标签: python xml python-3.x elementtree

尝试使用ElementTree解析包含未定义实体(即 )的XML:

ParseError: undefined entity  

在Python 2.x中,可以通过创建解析器(documentation)来更新XML实体dict:

parser = ET.XMLParser()
parser.entity["nbsp"] = unichr(160)

但是如何使用Python 3.x做同样的事情?


更新:我的方面存在误解,因为我忽略了我在尝试更新XML实体dict之前调用parser.parser.UseForeignDTD(1),这导致了解析器的错误。幸运的是,@ m.brindley耐心地指出XML实体dict仍然存在于Python 3.x中,可以像在Python 2.x中那样进行更新

2 个答案:

答案 0 :(得分:18)

这里的问题是XML中唯一有效的助记符实体是quotampaposltgt。这意味着必须使用entity declaration markup中定义的XML 1.1 spec在DTD中定义几乎所有(X)HTML命名实体。如果文档是独立的,则应使用内联DTD来完成,如下所示:

<?xml version="1.1" ?>
<!DOCTYPE naughtyxml [
    <!ENTITY nbsp "&#0160;">
    <!ENTITY copy "&#0169;">
]>
<data>
    <country name="Liechtenstein">
        <rank>1&nbsp;&gt;</rank>
        <year>2008&copy;</year>
        <gdppc>141100</gdppc>
        <neighbor name="Austria" direction="E"/>
        <neighbor name="Switzerland" direction="W"/>
    </country>
</data>

XMLParser中的xml.etree.ElementTree使用xml.parsers.expat进行实际解析。在XMLParser的init参数中,有一个“predefined HTML entities”的空格,但该参数尚未实现。在init方法中创建了一个名为entity的空dict,这是用于查找未定义实体的。

我不认为expat(通过扩展,ET XMLParser)能够处理切换命名空间到类似XHMTL的东西来解决这个问题。可能是因为它不会获取外部命名空间定义(我尝试将xmlns="http://www.w3.org/1999/xhtml"作为数据元素的默认命名空间,但它没有很好地发挥作用)但我无法确认。默认情况下,expat会针对非XML实体引发错误,但您可以通过定义外部DOCTYPE来解决此问题 - 这会导致expat解析器将未定义的实体条目传递回ET.XMLParser的{​​{1}}方法

_default()方法查找_default()实例中的entity dict,如果找到匹配的密钥,它将用相关值替换该实体。这维护了问题中提到的Python-2.x语法。

<强>解决方案:

  • 如果数据没有外部DOCTYPE并且有(X)HTML助记符实体,那么你运气不好。它是无效的XML和expat是正确的抛出错误。您应该添加外部DOCTYPE。
  • 如果数据具有外部DOCTYPE,您可以使用旧语法将助记符名称映射到字符。 注意:您应该在py3k中使用XMLParser - chr()不再是有效名称
    • 或者,您可以使用unichr()更新XMLParser.entity,将所有有效的HTML5助记符实体映射到其字符。
  • 如果数据是XHTML,您可以继承html.entities.html5来处理助记符实体,但这不会根据需要返回HTMLParser

以下是我使用的代码段 - 它使用外部DOCTYPE通过ElementTree解析XML(以演示如何通过子类化添加实体处理),HTMLParser使用实体映射和ET.XMLParser(由于外部DOCTYPE,它将默默地忽略未定义的实体)。有一个有效的XML实体(expat)和一个未定义的实体(&gt;),我使用&copy;映射到chr(0x24B4)

ET.XMLParser

答案 1 :(得分:2)

我遇到了类似的问题,并使用lxml解决了这个问题。它的etree.XMLParser有一个recover关键字参数,迫使它试图忽略损坏的XML。