Python xml etree 从 StringIO 源构建 DTD?

4 投票
2 回答
3228 浏览
提问于 2025-04-16 04:43

我正在调整以下代码(这个代码是根据这个问题的建议创建的),它的功能是将一个XML文件和它的DTD转换成另一种格式。在这个问题中,加载部分是最重要的:

xmldoc = open(filename)

parser = etree.XMLParser(dtd_validation=True, load_dtd=True)    
tree = etree.parse(xmldoc, parser)

在使用文件系统时,这个方法运行得很好,但我现在要把它转换成通过一个网络框架来运行,在这个框架中,这两个文件是通过一个表单加载的。

加载XML文件的部分运行得很好:

tree = etree.parse(StringIO(data['xml_file']) 

但是因为DTD在XML文件的顶部有链接,所以下面的语句就失败了:

parser = etree.XMLParser(dtd_validation=True, load_dtd=True)
tree = etree.parse(StringIO(data['xml_file'], parser)

根据这个问题,我尝试了:

etree.DTD(StringIO(data['dtd_file'])
tree = etree.parse(StringIO(data['xml_file'])

虽然第一行没有报错,但第二行在处理DTD应该识别的unicode实体时出错了(在文件系统版本中是可以正常工作的):

XMLSyntaxError: 实体 'eacute' 未定义,行 4495,列 46

我该如何正确加载这个DTD呢?

2 个回答

1

你可以试试用一个自定义解析器。文档里其实有个例子,教你怎么用这个来提供一个dtd。

5

这里有一个简短但完整的例子,使用了@Steven提到的自定义解析器技术。

from StringIO import StringIO
from lxml import etree

data = dict(
    xml_file = '''<?xml version="1.0"?>
<!DOCTYPE x SYSTEM "a.dtd">
<x><y>&eacute;zz</y></x>
''',
    dtd_file = '''<!ENTITY eacute "&#233;">
<!ELEMENT x (y)>
<!ELEMENT y (#PCDATA)>
''')

class DTDResolver(etree.Resolver):
     def resolve(self, url, id, context):
         return self.resolve_string(data['dtd_file'], context)

xmldoc = StringIO(data['xml_file'])
parser = etree.XMLParser(dtd_validation=True, load_dtd=True)
parser.resolvers.add(DTDResolver())
try:
    tree = etree.parse(xmldoc, parser)
except etree.XMLSyntaxError as e:
    # handle xml and validation errors

撰写回答