Python中有什么好的XML流解析器?

14 投票
3 回答
22880 浏览
提问于 2025-04-17 03:54

有没有可以在Python中解析文件流的XML解析器?我的XML文件太大,无法全部放进内存,所以我需要解析流。

理想情况下,我不想需要管理员权限来安装东西,所以lxml这个选项就不太合适。

我一直在使用xml.etree.ElementTree,但是我觉得它有问题,具体可以参考这个链接

3 个回答

12

你是在找xml.sax吗?它就在Python的标准库里。

22

这里有一个关于如何在处理超大XML文件时使用 不错的答案,它提到了 xml.etree.ElementTree.iterparse 的用法。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)
1

使用 xml.etree.cElementTree。这个比 xml.etree.ElementTree 快很多。它们两个都没有问题。问题出在你的文件上(可以看看我对你另一个问题的回答)。

撰写回答