如何在 Python3 中将 defusedxml 与 sax 一起使用?
How can I use defusedxml with sax in Python3?
我在 Python3 中构建了一个 XML 解析器,它使用 SAX 从一个长文件(可能是流式文件)中提取有用的信息;我将把我认为是我现有代码的相关部分放在这个 post 的底部。我正在 PubMed 的 XML 数据上测试我的解析器,这可能是安全的——但解析器可能会用于其他 XML 数据(对其查找的标签进行适当修改),并且 XML 可能不安全。
为了安全起见,我似乎应该使用 defusedxml library。描述是这是一个“猴子补丁”,IIUC 意味着 defusedxml.sax 库不提供功能,我可以(安全地,我希望!)使用常规 xml.sax 库。需要这样做的一个例子是我的元素处理程序,它必须被定义为使用 xml.sax 库,而不是 defusedxml.sax 库,因为后者不提供 'handler' class 我可以子class:
class ElementHandler(xml.sax.handler.ContentHandler):
因为 defusedxml.sax 库不提供 'handler'。另一方面,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 说
所有函数和解析器 classes 都接受三个额外的关键字参数。他们 return 或者
与原始函数或兼容子函数相同的对象classes.
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>
您可以将 forbid_dtd 设置为:
parser = defusedxml.sax.make_parser()
parser.forbid_dtd = True
但是正如您所建议的那样,它不会按照您的要求进行。您在这里想要的是禁用 forbid_external
设置:
parser = defusedxml.sax.make_parser()
parser.forbid_external = False
哪一个在加注ExternalReferenceForbidden
我在 Python3 中构建了一个 XML 解析器,它使用 SAX 从一个长文件(可能是流式文件)中提取有用的信息;我将把我认为是我现有代码的相关部分放在这个 post 的底部。我正在 PubMed 的 XML 数据上测试我的解析器,这可能是安全的——但解析器可能会用于其他 XML 数据(对其查找的标签进行适当修改),并且 XML 可能不安全。
为了安全起见,我似乎应该使用 defusedxml library。描述是这是一个“猴子补丁”,IIUC 意味着 defusedxml.sax 库不提供功能,我可以(安全地,我希望!)使用常规 xml.sax 库。需要这样做的一个例子是我的元素处理程序,它必须被定义为使用 xml.sax 库,而不是 defusedxml.sax 库,因为后者不提供 'handler' class 我可以子class:
class ElementHandler(xml.sax.handler.ContentHandler):
因为 defusedxml.sax 库不提供 'handler'。另一方面,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 说 所有函数和解析器 classes 都接受三个额外的关键字参数。他们 return 或者 与原始函数或兼容子函数相同的对象classes.
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>
您可以将 forbid_dtd 设置为:
parser = defusedxml.sax.make_parser()
parser.forbid_dtd = True
但是正如您所建议的那样,它不会按照您的要求进行。您在这里想要的是禁用 forbid_external
设置:
parser = defusedxml.sax.make_parser()
parser.forbid_external = False
哪一个在加注ExternalReferenceForbidden