Как обернуть правильную функцию генератора вокруг SAX Parser - PullRequest
0 голосов
/ 01 ноября 2010

У меня 35,5 Мб .XLSM файла.Когда фактический используемый контент расширяется, он затопляет DOM-парсеры, такие как дерево элементов, исчерпывающее память после долгого и длительного времени работы.

Однако при использовании SAX-парсера ContentHandler ограничивается накоплением строкво временном файле.Что немного раздражает, потому что синтаксический анализатор и основное приложение могут иметь простые сопутствующие отношения, где каждая строка, проанализированная SAX, может быть передана приложению.

Это не выглядиткак возможно следующее:

def gen_rows_from_xlsx( someFile ):
    myHandler= HandlerForXLSX()
    p= xml.sax.makeParser()
    p.setContentHandler( myHandler, some_kind_of_buffer )
    for row in some_kind_of_buffer.rows():
        p.parse() # Just enough to get to the ContentHandler's "buffer.put()"
        yield row

Периодически HandlerForXLSX будет вызывать some_kind_of_buffer.put( row ) для помещения строки в буфер.Эта единственная строка должна быть получена через some_kind_of_buffer.rows().

Простые соотношения сопрограммы между парсером SAX и gen_rows_from_xslx() были бы идеальными.

Я пропустил некоторую магию функции генератора, которая позволитмне упаковать SAX в качестве сопрограммы какой-то?

Является ли единственной альтернативой для создания потока синтаксического анализа SAX и использования Queue для получения строк, созданных синтаксическим анализатором?

Или проще перекусить пулю и создать временный файлв парсере SAX и затем выдавать эти объекты через генератор?

Related: Ленивый парсер SAX XML с остановкой / возобновлением .

Ответы [ 2 ]

5 голосов
/ 02 ноября 2010

"" "У меня 35,5 Мб .XLSM-файла. Когда фактический используемый контент расширяется, он затопляет DOM-парсеры, как дерево элементов, исчерпывающее память после долгого и длительного времени работы." ""

Я не понимаю этого.Вещи, которые вы должны использовать:

import xml.etree.cElementTree as ET

ET.iterparse(sourcefile) # sourcefile being a cStringIO.StringIO instance holding your worksheet XML document

element.clear() # leave only scorched earth behind you

В этой статье показано, как использовать iterparse и clear.

Пример: загрузка XLSX (100 МБ, большинствоиз которых две таблицы по 16 тыс. строк и около 200 столбцов каждая) в объектную модель xlrd:

Прошло около 4 минут [старый старый ноутбук [2 ГГц, одноядерный], работающий под управлением Windows XP и Python2,7].Инкрементное использование памяти максимально составляет около 300 МБ памяти, большая часть которой является выходной информацией, а не деревом элементов.

1 голос
/ 01 ноября 2010

Похоже, вы могли бы использовать интерфейс IncrementalParser для этого?Что-то вроде:

def gen_rows_from_xlsx(someFile):
    buf = collections.deque()
    myHandler = HandlerForXLSX(buf)
    p = xml.sax.make_parser()
    p.setContentHandler(myHandler)
    with open(someFile) as f:
        while True:
            d = f.read(BLOCKSIZE)
            if not d: break
            p.feed(d)
            while buf: yield buf.popleft()
    p.close()

Чтобы сделать это с parse, вам потребуется yield для нескольких кадров стека, что Python просто не поддерживает.

...