【问题标题】:What is a good XML stream parser for Python? [closed]什么是 Python 的优秀 XML 流解析器? [关闭]
【发布时间】:2011-12-03 08:37:16
【问题描述】:

是否有任何用于 Python 的 XML 解析器可以解析文件流?我的 XML 文件太大而无法放入内存,所以我需要解析流。

理想情况下,我不必拥有 root 访问权限来安装东西,所以lxml 不是一个很好的选择。

我一直在使用xml.etree.ElementTreeI am convinced it is broken

【问题讨论】:

    标签: python xml parsing stream


    【解决方案1】:

    您在寻找xml.sax 吗?它就在标准库中。

    【讨论】:

      【解决方案2】:

      使用xml.etree.cElementTree。它比xml.etree.ElementTree 快得多。它们都没有损坏。您的文件已损坏(请参阅我对您其他问题的回答)。

      【讨论】:

      • 确实,它要快得多。是的,我的文件坏了。
      • Guy 在询问流式解析器。
      • @mcepl:Guy 想解析大文件;家伙可以用iterparse() 做到这一点。 你的答案是什么/在哪里?
      • 不是 iterparse() 也在构建树(“请注意,iterparse 仍然构建树,就像解析器一样。”effbot.org/zone/element-iterparse.htm)。我的回答是撞倒彼得维克托林的那个。
      • 仅供参考:在 2019 年,cElementTree 只是 ElementTree 的别名。
      【解决方案3】:

      这是good answer 关于xml.etree.ElementTree.iterparse 在大型 XML 文件上的练习。 lxml 也有这个方法。使用iterparse 进行流解析的关键是手动清除和删除已处理的节点,否则最终会耗尽内存。

      另一个选项是使用xml.sax。官方手册对我来说太正式了,并且缺少示例,因此需要与问题一起进行澄清。默认解析器模块xml.sax.expatreader,实现增量解析接口xml.sax.xmlreader.IncrementalParser。也就是说xml.sax.make_parser()提供了合适的流解析器。

      例如,给定一个 XML 流,如:

      <?xml version="1.0" encoding="utf-8"?>
      <root>
        <entry><a>value 0</a><b foo='bar' /></entry>
        <entry><a>value 1</a><b foo='baz' /></entry>
        <entry><a>value 2</a><b foo='quz' /></entry>
        ...
      </root>
      

      可以通过以下方式处理。

      #!/usr/bin/env python
      # -*- coding: utf-8 -*-
      
      import xml.sax
      
      
      class StreamHandler(xml.sax.handler.ContentHandler):
      
        lastEntry = None
        lastName  = None
      
      
        def startElement(self, name, attrs):
          self.lastName = name
          if name == 'entry':
            self.lastEntry = {}
          elif name != 'root':
            self.lastEntry[name] = {'attrs': attrs, 'content': ''}
      
        def endElement(self, name):
          if name == 'entry':
            print({
              'a' : self.lastEntry['a']['content'],
              'b' : self.lastEntry['b']['attrs'].getValue('foo')
            })
            self.lastEntry = None
          elif name == 'root':
            raise StopIteration
      
        def characters(self, content):
          if self.lastEntry:
            self.lastEntry[self.lastName]['content'] += content
      
      
      if __name__ == '__main__':
        # use default ``xml.sax.expatreader``
        parser = xml.sax.make_parser()
        parser.setContentHandler(StreamHandler())
        # feed the parser with small chunks to simulate
        with open('data.xml') as f:
          while True:
            buffer = f.read(16)
            if buffer:
              try:
                parser.feed(buffer)
              except StopIteration:
                break
        # if you can provide a file-like object it's as simple as
        with open('data.xml') as f:
          parser.parse(f)
      

      【讨论】:

      • 谢谢你。感谢您的回答,我终于找到了自己问题的答案。查看我更详细的答案:stackoverflow.com/a/44398623/938111
      • 愚蠢的问题,time.sleep(2) 是干什么用的?
      • @gman 实际上这是一个好问题。很难记住else 分支背后的意图是什么。可能与尝试模拟慢速输入有关。但我复制粘贴了 sn-p 并用 raise RuntimeError 代替 time.sleep 调用运行它。它运行成功,所以它是一个死分支。删除它。
      猜你喜欢
      • 2010-11-29
      • 1970-01-01
      • 1970-01-01
      • 2011-07-05
      • 1970-01-01
      • 2011-06-30
      • 1970-01-01
      • 2010-10-21
      • 1970-01-01
      相关资源
      最近更新 更多