代码之家  ›  专栏  ›  技术社区  ›  Peter Gibson

python中解析(流)XML的非阻塞方法

  •  7
  • Peter Gibson  · 技术社区  · 15 年前

    我有一个XML文档通过一个套接字传入,我需要动态解析和响应它(即解析部分树)。我想要的是这样做的非阻塞方法,这样我就可以在等待更多数据进入时做其他事情(无需线程)。

    如果在读取缓冲区为空时完成迭代,则类似于iterparse的内容将非常理想,例如:

    context = iterparse(imaginary_socket_file_wrapper)
    while 1:
        for event, elem in context:
            process_elem(elem)
        # iteration of context finishes when socket has no more data
        do_other_stuff()
        time.sleep(0.1)
    

    我想SAX也是一种选择,但iterparse似乎更适合我的需要。有什么想法吗?

    更新:

    使用线程是很好的,但引入了我希望避开的复杂性级别。我认为非阻塞调用是一种很好的方法,但我发现它增加了解析XML的复杂性。

    3 回复  |  直到 15 年前
        1
  •  8
  •   Peter Gibson    14 年前

    潜入iterparse源为我提供了解决方案。下面是一个简单的示例,演示如何动态构建XML树并在元素的关闭标记后处理元素:

    import xml.etree.ElementTree as etree
    
    parser = etree.XMLTreeBuilder()
    
    def end_tag_event(tag):
        node = self.parser._end(tag)
        print node
    
    parser._parser.EndElementHandler = end_tag_event
    
    def data_received(data):
        parser.feed(data)
    

    在我的例子中,我最终从twisted向它提供数据,但它也应该使用非阻塞套接字。

        2
  •  4
  •   edarc    15 年前

    我认为这有两个组件,非阻塞网络I/O和面向流的XML解析器。

    对于前者,您必须选择一个非阻塞网络框架,或者为此推出您自己的解决方案。Twisted当然会起作用,但我个人觉得控制框架的反转很难让我的大脑思考。您可能需要跟踪回调中的许多状态,以向解析器提供反馈。出于这个原因,我倾向于 Eventlet 更容易编程,我认为它非常适合这种情况。

    本质上,它允许您编写代码 犹如 您使用的是阻塞套接字调用(使用普通循环、生成器或任何您喜欢的方法),但您可以将其生成一个单独的协程(“greenlet”),当I/O操作阻塞时,该协程将自动执行协作产出,从而允许其他协程运行。

    这使得使用任何面向流的解析器再次变得微不足道,因为代码的结构类似于普通的阻塞调用。这还意味着许多不直接处理套接字或其他I/O(例如解析器)的库不必经过特殊修改而成为非阻塞库:如果它们阻塞,Eventlet将生成协同路由。

    轻微地 magic,但我发现它的学习曲线比Twisted简单得多,并且生成的代码更简单,因为您不必将逻辑“由内而外”地转换以适应框架。

        3
  •  1
  •   wbg    15 年前

    如果不使用线程,可以使用事件循环并轮询非阻塞套接字。

    asyncore Twisted 这个 Python的异步库,但对于您的需要,它比较复杂,可能有点重。

    或者, multiprocessing

    无论如何,我认为您将不得不使用线程、额外的进程或编织一些同样复杂的异步魔法。