Генерация очень больших файлов XML в Python? - PullRequest
8 голосов
/ 16 июня 2010

Кто-нибудь знает эффективный способ памяти для создания очень больших файлов XML (например, 100-500 МБ) в Python?

Я использовал lxml , но использование памяти не за горами.

Ответы [ 4 ]

8 голосов
/ 16 июня 2010

Возможно, вы могли бы использовать шаблонизатор вместо генерации / сборки 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 МБ XML-файл, без проблем с памятью. (согласно диспетчеру задач Windows он оставался постоянным на уровне около 10 МБ)

В зависимости от ваших потребностей, это может быть более дружественный и более быстрый способ генерирования xml, чем использование SAX и т. Д. эти два в качестве примера)

2 голосов
/ 16 июня 2010

Очевидно, что вам нужно избегать построения целого дерева (DOM или Etree или чего-либо еще) в памяти.Но лучший способ зависит от источника ваших данных и от того, насколько сложна и взаимосвязана структура вашего вывода.

Если он большой, потому что в нем тысячи экземпляров довольно независимых элементов, вы можете сгенерировать внешнюю оболочку., а затем построить деревья для каждого элемента и затем сериализовать каждый фрагмент в выходной.

Если фрагменты не настолько независимы, вам нужно будет провести дополнительную бухгалтерию - например, управлять базой данных сгенерированных идентификаторов и идентификаторов.

Я бы разбил его на 2 или 3 части: производитель событий саксофона, выходной сериализатор, использующий события саксофона, и, если нужно, проще работать с некоторыми независимыми частями, такими как объекты или деревья, что-то, чтобы построить ихобъекты, а затем превратить их в события саксофона для сериализатора.

Возможно, вы могли бы просто управлять всем этим как прямым выводом текста, вместо того, чтобы иметь дело с саксофонными событиями: это зависит от того, насколько это сложно.

Это также может быть хорошим местом для использования генераторов Python в качестве способа потоковой передачи выходных данных без необходимости создания больших структур в памяти.

2 голосов
/ 16 июня 2010

Единственный разумный способ создать такой большой XML-файл - это построчно, что означает печать во время работы конечного автомата, и лот тестирования.

0 голосов
/ 16 июня 2010

Если ваш документ очень обычный (например, набор записей в базе данных, все в одном формате), вы можете использовать мою собственную библиотеку "xe".

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

Библиотека xe была разработана для создания синдикационных каналов (Atom, RSS и т. Д.), И я думаю, что она проста в использовании. Мне нужно обновить его для Python 2.6, но я пока не сожалею об этом.

...