在Python3中如何将defusedxml与sax一起使用?

2024-10-05 15:18:18 发布

您现在位置:Python中文网/ 问答频道 /正文

我在Python3中构建了一个XML解析器,它使用SAX从一个长文件(可能是流文件)中提取有用的信息;我将把我认为是我现有代码的相关部分放在这篇文章的底部。我正在PubMed的XML数据上测试解析器,这可能是安全的——但解析器可能会用于其他XML数据(对它寻找的标记进行适当修改),而XML可能不安全

看来我应该用defusedxml library来保证安全。描述是这是一个“猴子补丁”,这意味着如果defusedxml.sax库不提供功能,我可以(安全地,我希望!)使用常规的xml.sax库。需要这样做的一个例子是我的元素处理程序,它必须定义为使用xml.sax库,而不是defusedxml.sax库,因为后者不提供我可以子类化的“handler”类:

class ElementHandler(xml.sax.handler.ContentHandler):

因为defusedxml.sax库不提供“处理程序”。另一方面,defusedxml.sax库确实提供了make_parser()的定义,我使用它

但是,当我尝试运行代码时(如果不安全,只要使用标准xml.sax库,代码就可以正常运行),我会遇到一个异常:

raise ExternalReferenceForbidden(context, base, sysid, pubid)
        defusedxml.common.ExternalReferenceForbidden: 
     ExternalReferenceForbidden(system_id='http://dtd.nlm.nih.gov/ncbi/pubmed/out/pubmed_190101.dtd', 
                                public_id=None)

当我的解析器读取PubMed XML文件的第二行时,显然会发生这种情况:

<!DOCTYPE PubmedArticleSet SYSTEM "http://dtd.nlm.nih.gov/ncbi/pubmed/out/pubmed_190101.dtd">

好的,那么如何解决这个问题呢?直觉上,我希望它忽略这个DOCTYPE声明。但是怎么做呢

这个documentation 说 所有函数和解析器类都接受三个额外的关键字参数。他们要么返回 与原始函数或兼容子类相同的对象

   forbid_dtd (default: False)
   disallow XML with a <!DOCTYPE> processing instruction and 
   raise a DTDForbidden exception when a DTD processing instruction 
   is found.

但我有两个问题:1)我不希望它引发异常,我只希望它忽略声明;2)我不知道该把这个关键词放在哪里。如果我把它放在我的调用中,使_parser():

   defusedxml.sax.make_parser(forbid_dtd=True)

我明白了

   TypeError: make_parser() got an unexpected keyword argument 'forbid_dtd'

同样地,在其他地方,我也试着把它放进去

我已经查找了示例代码,但没有找到任何有用的东西,也没有找到任何可以解决此问题的问题。有this,但这是一个难题——在没有DOCTYPE声明的情况下重新编写传入的XML文件,然后(我想)用SAX解析新文件。在处理大型XML文档时不是很实用

所以我的问题是:如何使用defusedxml库构建SAX解析器,并告诉它忽略DOCTYPE声明

------我的代码摘录如下--------

def ProcessXMLFile(<some parameters here>
    SAXParser = defusedxml.sax.make_parser()
    SAXParser.setContentHandler(ElementHandler(<my startup parameters here>)
    ContentHandler = SAXParser.getContentHandler()
    Input = xml.sax.InputSource()
    Input.setCharacterStream(strXMLFile)
    Input.setEncoding('utf-8')
    SAXParser.parse(Input.getCharacterStream())

class ElementHandler(xml.sax.handler.ContentHandler):
    <__init__(), startElement(), endElement() etc. here>

Tags: 文件代码声明parser解析器inputmakexml