我一直在尝试解析一些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.Thread
和Queue.Queue
,但是这会导致线程的各种问题,这些问题实际上让我分散了我正在努力解决的实际问题。
我知道我可以在一个单独的进程中运行SAX解析器,但我觉得必须有一种更简单的方法来获取数据。有吗?
答案 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“产生”结果:
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.send
,printer
中的代码将一直执行,直到达到下一个(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)