【问题标题】:How can I use defusedxml with sax in Python3?如何在 Python3 中将 defusedxml 与 sax 一起使用?
【发布时间】:2023-03-19 19:20:01
【问题描述】:

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

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

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) 我不知道在哪里放置这个关键字。如果我把它放在我对 make_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>

【问题讨论】:

    标签: python xml sax doctype


    【解决方案1】:

    你可以设置 forbid_dtd:

    parser =  defusedxml.sax.make_parser()
    parser.forbid_dtd = True
    

    但正如你所建议的,它不会做你想做的事。您想要在这里禁用forbid_external 设置:

    parser =  defusedxml.sax.make_parser()
    parser.forbid_external = False
    

    这是提高ExternalReferenceForbidden的人

    【讨论】:

    • 我得回头看看我在哪里使用它...项目已经结束,但我仍然有数据和程序。因此,虽然我现在无法测试您的建议,但听起来不错,并且我接受了您的回答。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2016-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-19
    • 2016-11-01
    • 2016-05-18
    相关资源
    最近更新 更多