如何围绕SAX Parser包装适当的生成器函数

时间:2010-11-01 18:25:42

标签: python sax

我有35.5Mb .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解析器中创建一个临时文件,然后通过生成器生成这些对象?

相关:Lazy SAX XML parser with stop/resume

2 个答案:

答案 0 :(得分:5)

“”“我有35.5Mb .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

This article显示了如何使用iterparseclear

示例:将XLSX(100Mb,大部分是两个工作表,每个工作表大约有16K行,大约200个col)加载到xlrd对象模型中:

经过约4分钟的时间[打败旧笔记本电脑[2 GHz单核]运行Windows XP和Python 2.7]。增量内存使用量最大约为300Mb内存,其中大部分是输出,而不是元素树。

答案 1 :(得分:1)

好像你可以使用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根本不支持的内容。