【问题标题】:Generating very large XML files in Python?在 Python 中生成非常大的 XML 文件?
【发布时间】:2011-03-04 05:07:47
【问题描述】:

有谁知道在 Python 中生成非常大的 xml 文件(例如 100-500 MiB)的内存高效方法?

我一直在使用 lxml,但内存使用量已超标。

【问题讨论】:

  • 这是个好主意吗?什么会使用这样的文件?
  • 500MiB XML 文件?哎呀——如果我的 XML 文件达到 500MiB,我会考虑使用更高效的文件格式! :-)
  • 输出文档有多复杂?你从哪里得到输入数据?输入到输出的转换有多复杂?
  • 您是否考虑过是否可以将其分解为更易于管理的部分并使用 Xinclude ?我猜这取决于什么样的进程将消耗这个大文件,因为关键不是在最后将 xincludes 处理成一个大文件,而是让最终的消费者进程动态处理 xincludes .不知道该模型是否适合您的工作流程,但如果适合,它可以使其更易于管理。 (我很难想象 500MB 的 xml 文件会使用什么样的进程!;-)

标签: python xml lxml


【解决方案1】:

也许您可以使用模板引擎而不是自己生成/构建 xml?

Genshi 例如基于 xml 并支持流输出。一个非常基本的例子:

from genshi.template import MarkupTemplate

tpl_xml = '''
<doc xmlns:py="http://genshi.edgewall.org/">
<p py:for="i in data">${i}</p>
</doc>
'''

tpl = MarkupTemplate(tpl_xml)
stream = tpl.generate(data=xrange(10000000))

with open('output.xml', 'w') as f:
    stream.render(out=f)

这可能需要一段时间,但内存使用率仍然很低。

Mako 模板引擎(不是“本机”xml)的相同示例,但要快得多:

from mako.template import Template
from mako.runtime import Context

tpl_xml = '''
<doc>
% for i in data:
<p>${i}</p>
% endfor
</doc>
'''

tpl = Template(tpl_xml)

with open('output.xml', 'w') as f:
    ctx = Context(f, data=xrange(10000000))
    tpl.render_context(ctx)

最后一个示例在我的笔记本电脑上运行了大约 20 秒,生成了一个(诚然非常简单)151 MB 的 xml 文件,完全没有内存问题。 (根据 Windows 任务管理器,它保持在 10MB 左右)

根据您的需要,这可能是一种比使用 SAX 等更友好、更快速的生成 xml 的方式...查看文档以了解您可以使用这些引擎做什么(还有其他引擎,我刚刚挑选出来以这两个为例)

【讨论】:

  • 好主意!这绝对值得考虑。
【解决方案2】:

生成如此大的 XML 文件的唯一合理方法是逐行生成,这意味着在运行状态机的同时进行打印,并进行 大量 测试。

【讨论】:

    【解决方案3】:

    显然,您必须避免在内存中构建整个树(无论是 DOM 还是 etree 或其他)。但最好的方法取决于数据的来源以及输出结构的复杂程度和相互关联的程度。

    如果它很大,因为它有数千个相当独立的项目实例,那么您可以生成外包装,然后为每个项目构建树,然后将每个片段序列化到输出。

    如果片段不是那么独立,那么您需要做一些额外的簿记——比如管理生成的 ids 和 idrefs 的数据库。

    我会将它分成 2 或 3 个部分:一个 sax 事件生成器、一个输出序列化器 吃 sax 事件,并且可选地,如果使用一些独立的部分作为对象或树似乎更容易,则构建这些对象然后将它们转换为序列化程序的 sax 事件。

    也许您可以将其全部作为直接文本输出进行管理,而不是处理 sax 事件:这取决于它的复杂程度。

    这也可能是使用 python 生成器作为流输出的一种方式,而无需在内存中构建大型结构的好地方。

    【讨论】:

    • 嗯,是的,它将有数千个相当独立的项目实例。我想我可能会采用这种方法。谢谢。
    • 上面建议的模板方法可能更容易——特别是如果单独的对象/块足够小可以处理。如果事情不容易分成足够小的块,则可以使用 python 生成器将 SAX 生产者/消费者对作为协同例程运行。
    【解决方案4】:

    如果你的文档非常规则(比如一堆数据库记录,格式都一样)你可以使用我自己的“xe”库。

    http://home.avvanta.com/~steveha/xe.html

    xe 库是为生成联合提要(Atom、RSS 等)而设计的,我认为它很容易使用。我需要为 Python 2.6 更新它,但我还没有,对此感到抱歉。

    【讨论】:

    • 非常好。这比使用 lxml 更节省内存吗?
    • 不确定。我还没有看过lxml。如果您一次持有所有数据,那么无论如何您至少持有 500 MiB。但是如果你在一个循环中写东西,你可以重用相同的 xe 数据结构,这样可以节省内存。但也许你可以用 lxml 做同样的事情?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-14
    • 1970-01-01
    • 1970-01-01
    • 2013-02-28
    • 2013-09-27
    • 1970-01-01
    • 2011-07-23
    相关资源
    最近更新 更多