简体   繁体   English

使用 lxml 解析大型 XML 文件

[英]Parsing large XML file with lxml

I am trying to parse the dblp.xml file(3.2gb) using lxml.我正在尝试使用 lxml 解析 dblp.xml 文件(3.2gb)。 The following below is my code.以下是我的代码。

from lxml import etree
from io import StringIO, BytesIO
tree = etree.parse("dblp.xml")

However I get an error stating:但是我收到一条错误消息:

OSError                                   Traceback (most recent call last)
<ipython-input-5-6a342013a160> in <module>
      1 from lxml import etree
      2 from io import StringIO, BytesIO
----> 3 tree = etree.parse("dblp.xml")

src/lxml/etree.pyx in lxml.etree.parse()

src/lxml/parser.pxi in lxml.etree._parseDocument()

src/lxml/parser.pxi in lxml.etree._parseDocumentFromURL()

src/lxml/parser.pxi in lxml.etree._parseDocFromFile()

src/lxml/parser.pxi in lxml.etree._BaseParser._parseDocFromFile()

src/lxml/parser.pxi in lxml.etree._ParserContext._handleParseResultDoc()

src/lxml/parser.pxi in lxml.etree._handleParseResult()

src/lxml/parser.pxi in lxml.etree._raiseParseError()

OSError: Error reading file 'dblp.xml': failed to load external entity "dblp.xml"

Both dblp.xml and dblp.dtd is in the root folder already. dblp.xml 和 dblp.dtd 都已经在根文件夹中。

Please help!请帮忙!

You can use etree.iterparse to avoid loading the whole file in memory:您可以使用etree.iterparse来避免在 memory 中加载整个文件:

events = ("start", "end")
with open("dblp.xml", "r") as fo:
    context = etree.iterparse(fo, events=events)
    for action, elem in context:
        # Do something

This will allow you to only extract entities you need while ignoring others.这将允许您只提取您需要的实体而忽略其他实体。

As Jan Jaap Meijerink stated, you may try to use iterparse.正如 Jan Jaap Meijerink 所说,您可以尝试使用 iterparse。 Possibly you could also disable lxml security features preventing parsing huge files (see documentation at https://lxml.de/api/lxml.etree.XMLParser-class.html ):可能您还可以禁用防止解析大文件的 lxml 安全功能(请参阅https://lxml.de/api/lxml.etree.XMLParser-class.html的文档):

with open('', 'r') as fobj:
    for event, elem in  etree.iterparse(
                    fobj,
                    huge_tree=True,
                ):
            #do something with element or event

Eventually, if you prefer trying use of parse, you may define xml parser with huge_tree enabled and set it as default for further usages of etree.parse:最后,如果您更喜欢尝试使用 parse,您可以定义 xml 解析器并启用 huge_tree 并将其设置为默认值,以便进一步使用 etree.parse:

xml_parser_settings = dict(
    huge_tree=True, # resolve_entities=False, remove_pis=True, no_network=True
)

XMLPARSER = etree.XMLParser(xml_parser_settings)
etree.set_default_parser(XMLPARSER)

After those statements you may use etree.parser with configured XMLPARSER.在这些语句之后,您可以将 etree.parser 与配置的 XMLPARSER 一起使用。 Beware of multithreading, though ( https://lxml.de/1.3/api/lxml.etree-module.html#set_default_parser ).不过要小心多线程( https://lxml.de/1.3/api/lxml.etree-module.html#set_default_parser )。

Adding resolve_entities, remove_pis and no_network keyword may (at least a bit) reduce your risk of parsing huge extarnal files, if they come from untrusted source.添加 resolve_entities、remove_pis 和 no_network 关键字可以(至少在一定程度上)降低解析巨大外部文件的风险,如果它们来自不受信任的来源。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM