如何从Python SAX解析器返回数据?

时间:2012-01-15 21:47:57

标签: python xml sax

我一直在尝试解析一些LXML无法理解的巨大XML文件,所以我不得不用xml.sax解析它们。

class SpamExtractor(sax.ContentHandler):
    def startElement(self, name, attrs):
        if name == "spam":
            print("We found a spam!")
            # now what?

问题是我不明白如何实际return,或更好,yield,这个处理程序找到调用者的东西,而不等待整个文件被解析。到目前为止,我一直在讨论threading.ThreadQueue.Queue,但是这会导致线程的各种问题,这些问题实际上让我分散了我正在努力解决的实际问题。

我知道我可以在一个单独的进程中运行SAX解析器,但我觉得必须有一种更简单的方法来获取数据。有吗?

4 个答案:

答案 0 :(得分:6)

我认为我会将此作为另一个答案,因为它是一种完全不同的方法。

您可能需要查看xml.etree.ElementTree.iterparse,因为它似乎可以执行更多操作:

  

以递增方式将XML部分解析为元素树,并报告用户正在进行的操作。 source是包含XML数据的文件名或文件对象。 events是要报告的事件列表。如果省略,则仅报告“结束”事件。 parser是一个可选的解析器实例。如果没有给出,则使用标准XMLParser解析器。返回提供(event,elem)对的迭代器。

然后,您可以编写一个生成器,使用该迭代器,执行您想要的操作,并生成所需的值。

e.g:

def find_spam(xml):
    for event, element in xml.etree.ElementTree.iterparse(xml):
        if element.tag == "spam":
            print("We found a spam!")
            # Potentially do something
            yield element

差异主要在于你想要什么。 ElementTree的迭代器方法更多地是关于收集数据,而SAX方法更多的是关于它的行为。

答案 1 :(得分:5)

David Beazley demonstrates如何使用协程从sax ContentHandler“产生”结果:

cosax.py

import xml.sax

class EventHandler(xml.sax.ContentHandler):
    def __init__(self,target):
        self.target = target
    def startElement(self,name,attrs):
        self.target.send(('start',(name,attrs._attrs)))
    def characters(self,text):
        self.target.send(('text',text))
    def endElement(self,name):
        self.target.send(('end',name))

def coroutine(func):
    def start(*args,**kwargs):
        cr = func(*args,**kwargs)
        cr.next()
        return cr
    return start

# example use
if __name__ == '__main__':
    @coroutine
    def printer():
        while True:
            event = (yield)
            print event

    xml.sax.parse("allroutes.xml",
                  EventHandler(printer()))

以上,每次调用self.target.send时,printer内的代码都从event = (yield)开始运行。 event的参数已分配self.target.sendprinter中的代码将一直执行,直到达到下一个(yield),类似于生成器的工作方式。

虽然生成器通常由for-loop驱动,但协程(例如printer)由send次呼叫驱动。

答案 2 :(得分:0)

我的理解是SAX解析器用于完成工作,而不仅仅是将数据传递回食物链。

e.g:

class SpamExtractor(sax.ContentHandler):
    def __init__(self, canning_machine):
        self.canning_machine = canning_machine

    def startElement(self, name, attrs):
        if name == "spam":
            print("We found a spam!")
            self.canning_machine.can(name, attrs)

答案 3 :(得分:0)

基本上有三种解析XML的方法:

  1. SAX - 方法:它是访问者模式的一个实现,其想法是将事件推送到您的代码中。
  2. StAX - approach:只要你准备就可以拉下一个元素(对于部分解析很有用,即只读取SOAP头)
  3. DOM - 方法,将所有内容加载到内存中的树中
  4. 您似乎需要第二个,但我不确定它是否在标准库中的某个位置。