Python 使用(X)个HTML实体解析XML

Python 使用(X)个HTML实体解析XML,python,xml,python-3.x,elementtree,Python,Xml,Python 3.x,Elementtree,尝试使用ElementTree解析包含未定义实体(即)的XML会引发: ParseError:未定义的实体 在Python 2.x中,可以通过创建解析器()来更新XML实体dict: 但是如何在Python3.x上实现同样的功能呢 更新:我这边有一个误解,因为我忽略了在尝试更新XML实体dict之前调用parser.parser.UseForeignDTD(1),这会导致解析器出错。幸运的是,@m.brindley耐心地指出,XML实体dict仍然存在于Python 3.x中,并且可以以与Py

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

ParseError:未定义的实体

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

但是如何在Python3.x上实现同样的功能呢



更新:我这边有一个误解,因为我忽略了在尝试更新XML实体dict之前调用
parser.parser.UseForeignDTD(1)
,这会导致解析器出错。幸运的是,@m.brindley耐心地指出,XML实体dict仍然存在于Python 3.x中,并且可以以与Python 2.x相同的方式更新。这里的问题是,XML中唯一有效的助记符实体是
quot
amp
apos
lt
gt
。这意味着几乎所有(X)个HTML命名实体都必须在DTD中使用中定义的来定义。如果文档是独立的,则应使用内联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>

我有一个类似的问题,并通过使用。它的
etree.XMLParser
有一个
recover
关键字参数,该参数迫使它尝试忽略已损坏的XML。

感谢您探索这个问题,但我怀疑Python 3.x SPL是否允许更新XML entities表。至少我找不到这样的公告。很抱歉,使用regex准备远程XHTML数据作为一个想法是不可接受的。我有更多的时间来处理这个问题,并找出了expat为什么没有传递到
XMLParser
中的
\u default()
方法。查看我的编辑-如果定义了外部DOCTYPE,您就可以映射实体。我希望这个问题更一般,但让我们更“本地”地过滤这个问题:我有带有
xhtml1 transitional.dtd的XHTML数据,我预先知道只有未定义的XML实体是
。默认情况下,我使用lxml,如果不可用,则返回SPL,但返回ET。解析失败的具体原因是什么?如果XMLParser获取传递给它的未定义实体并且无法映射它,则引发的错误类似于“未定义实体%s:行%d列%d”,如果expat未传递它,则不包括%s。这已经包含在我的问题中:
ParseError:undefined entity
<?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>
from html.parser import HTMLParser
from html.entities import name2codepoint
import xml.etree.ElementTree as ET
import xml.parsers.expat as expat

xml = '''<?xml version="1.0"?>
<!DOCTYPE data PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<data>
    <country name="Liechtenstein">
        <rank>1&gt;</rank>
        <year>2008&copy;</year>
        <gdppc>141100</gdppc>
        <neighbor name="Austria" direction="E"/>
        <neighbor name="Switzerland" direction="W"/>
    </country>
</data>'''

# HTMLParser subclass which handles entities
print('=== HTMLParser')
class MyHTMLParser(HTMLParser):
    def handle_starttag(self, name, attrs):
        print('Start element:', name, attrs)
    def handle_endtag(self, name):
        print('End element:', name)
    def handle_data(self, data):
        print('Character data:', repr(data))
    def handle_entityref(self, name):
        self.handle_data(chr(name2codepoint[name]))

htmlparser = MyHTMLParser()
htmlparser.feed(xml)


# ET.XMLParser parse
print('=== XMLParser')
parser = ET.XMLParser()
parser.entity['copy'] = chr(0x24B8)
root = ET.fromstring(xml, parser)
print(ET.tostring(root))
for elem in root:
    print(elem.tag, ' - ', elem.attrib)
    for subelem in elem:
        print(subelem.tag, ' - ', subelem.attrib, ' - ', subelem.text)

# Expat parse
def start_element(name, attrs):
    print('Start element:', name, attrs)
def end_element(name):
    print('End element:', name)
def char_data(data):
    print('Character data:', repr(data))
print('=== Expat')
expatparser = expat.ParserCreate()
expatparser.StartElementHandler = start_element
expatparser.EndElementHandler = end_element
expatparser.CharacterDataHandler = char_data
expatparser.Parse(xml)