the*_*eta 15 python xml elementtree python-3.x
尝试使用ElementTree解析包含未定义实体(即 )的XML :
ParseError: undefined entity
在Python 2.x中,可以通过创建解析器(文档)来更新XML实体dict :
parser = ET.XMLParser()
parser.entity["nbsp"] = unichr(160)
Run Code Online (Sandbox Code Playgroud)
但是如何用Python 3.x做同样的事情呢?
更新:我的方面存在误解,因为我parser.parser.UseForeignDTD(1)在尝试更新XML实体dict之前忽略了我的调用,这导致了解析器的错误.幸运的是,@ m.brindley耐心地指出,XML实体dict仍然存在于Python 3.x中,并且可以像在Python 2.x中那样进行更新.
m.b*_*ley 18
这里的问题是,在XML唯一有效的助记实体quot,amp,apos,lt和gt.这意味着几乎所有(X)HTML命名实体都必须使用XML 1.1规范中定义的实体声明标记在DTD中定义.如果文档是独立的,这应该使用内联DTD来完成,如下所示:
<?xml version="1.1" ?>
<!DOCTYPE naughtyxml [
<!ENTITY nbsp " ">
<!ENTITY copy "©">
]>
<data>
<country name="Liechtenstein">
<rank>1 ></rank>
<year>2008©</year>
<gdppc>141100</gdppc>
<neighbor name="Austria" direction="E"/>
<neighbor name="Switzerland" direction="W"/>
</country>
</data>
Run Code Online (Sandbox Code Playgroud)
该XMLParser在xml.etree.ElementTree使用一个xml.parsers.expat做实际的解析.在init参数中XMLParser,有一个" 预定义HTML实体 " 的空间,但该参数尚未实现.entity在init方法中创建一个名为空的dict ,这是用于查找未定义实体的内容.
我不认为expat(通过扩展,ET XMLParser)能够处理切换命名空间到类似XHMTL的东西来解决这个问题.可能是因为它不会获取外部命名空间定义(我尝试xmlns="http://www.w3.org/1999/xhtml"为数据元素创建默认命名空间但它没有很好地运行)但我无法确认.默认情况下,外籍人士将提高对非XML实体错误,但你可以通过定义外部DOCTYPE绕开这个问题-这将导致Expat解析器传递未定义的实体条目回ET.XMLParser的_default()方法.
该_default()方法entity在XMLParser实例中查找dict ,如果找到匹配的键,它将用相关的值替换实体.这维护了问题中提到的Python-2.x语法.
解决方案:
chr()在py3k中使用- unichr()不再是有效名称
XMLParser.entity与html.entities.html5所有有效的HTML5记忆实体映射到自己的角色.HTMLParser来处理助记符实体,但这不会返回ElementTree所需的.这是我使用的代码片段 - 它通过外部DOCTYPE解析XML HTMLParser(通过子类化演示如何添加实体处理),ET.XMLParser实体映射和expat(由于外部DOCTYPE,它将默默地忽略未定义的实体).有一个有效的XML实体(>)和一个未定义的实体(©),我chr(0x24B4)用它映射到ET.XMLParser.
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></rank>
<year>2008©</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)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
8165 次 |
| 最近记录: |