我想解析一个大的XML文件,“即时”。我想使用一个python生成器来执行此操作。我试过了“xml.etree.cElementTree”的“iterparse”(这真的很不错),但仍然不是一个生成器。python:是否有XML解析器作为生成器实现?
其他建议?
我想解析一个大的XML文件,“即时”。我想使用一个python生成器来执行此操作。我试过了“xml.etree.cElementTree”的“iterparse”(这真的很不错),但仍然不是一个生成器。python:是否有XML解析器作为生成器实现?
其他建议?
“即时”解析和文档树并不真正兼容。 SAX风格的解析器通常用于此(例如,Python的标准xml.sax)。你基本上必须用startElement,endElement等各种事件的处理程序定义一个类,解析器将在解析XML文件时调用这些方法。
PullDom做你想要的。它从流中读取XML,如SAX,但是随后为其中选定的一部分构建DOM。
“PullDOM是一个非常简单的API,用于以流(高效!)方式处理DOM对象,而不是一个单一的树。”
所以如果我在for循环中加入“yield”语句(例如for事件中的(event,node):yield(event,node)}下次我进入for-loop时,PullDom不会重新启动? – jldupont 2009-10-03 12:33:37
...因为这就是“iterparse”发生的事情...... – jldupont 2009-10-03 12:34:33
@ Jean-Lou Dupont:如果你想要迭代器行为,也许你应该在ElementTree对象上调用'iter(...)'? – u0b34a0f6ae 2009-10-03 12:41:45
xml.etree.cElementTree
靠近正确用法的发电机;默认情况下,您会在“结束”事件之后收到每个元素,此时您可以处理它。如果处理后不需要它,则应该在元素上使用element.clear();从而节省内存。
这里是一个完整的例子,我的意思是,我解析Rhythmbox(音乐播放器)库。我使用(c)ElementTree的iterparse,并为每个处理过的元素调用element.clear(),这样我可以节省大量的内存。 (顺便说一句,下面的代码是一些萨克斯代码的继承者做同样的事情; cElementTree解决方案是一种解脱,因为1)代码是简洁的,并表达我所需要的,甚至更多2)它是3倍速度,3)它使用较少的内存。)
import os
import xml.etree.cElementTree as ElementTree
NEEDED_KEYS= set(("title", "artist", "album", "track-number", "location",))
def _lookup_string(string, strmap):
"""Look up @string in the string map,
and return the copy in the map.
If not found, update the map with the string.
"""
string = string or ""
try:
return strmap[string]
except KeyError:
strmap[string] = string
return string
def get_rhythmbox_songs(dbfile, typ="song", keys=NEEDED_KEYS):
"""Return a list of info dictionaries for all songs
in a Rhythmbox library database file, with dictionary
keys as given in @keys.
"""
rhythmbox_dbfile = os.path.expanduser(dbfile)
lSongs = []
strmap = {}
# Parse with iterparse; we get the elements when
# they are finished, and can remove them directly after use.
for event, entry in ElementTree.iterparse(rhythmbox_dbfile):
if not (entry.tag == ("entry") and entry.get("type") == typ):
continue
info = {}
for child in entry.getchildren():
if child.tag in keys:
tag = _lookup_string(child.tag, strmap)
text = _lookup_string(child.text, strmap)
info[tag] = text
lSongs.append(info)
entry.clear()
return lSongs
现在,我不明白你的期望,你有以下期待?
# take one
for event, entry in ElementTree.iterparse(rhythmbox_dbfile):
# parse some entries, then exit loop
# take two
for event, entry in ElementTree.iterparse(rhythmbox_dbfile):
# parse the rest of entries
每次调用iterparse时,都会得到一个新的迭代器对象,重新读取该文件!如果你想用迭代器语义的持久化对象,你必须是指在两个环相同的对象(未试过的代码):
#setup
parseiter = iter(ElementTree.iterparse(rhythmbox_dbfile))
# take one
for event, entry in parseiter:
# parse some entries, then exit loop
# take two
for event, entry in parseiter:
# parse the rest of entries
我认为这可能会造成混淆,因为不同的对象有不同的语义。一个文件对象将始终有一个内部状态并在文件中前进,但是您可以对其进行迭代。 ElementTree iterparse对象显然不是。关键是认为当你使用for循环时,for总是在你迭代的东西上调用iter()。这里是一个文件对象比较ElementTree.iterparse一个实验:
>>> import xml.etree.cElementTree as ElementTree
>>> pth = "/home/ulrik/.local/share/rhythmbox/rhythmdb.xml"
>>> iterparse = ElementTree.iterparse(pth)
>>> iterparse
<iterparse object at 0x483a0890>
>>> iter(iterparse)
<generator object at 0x483a2f08>
>>> iter(iterparse)
<generator object at 0x483a6468>
>>> f = open(pth, "r")
>>> f
<open file '/home/ulrik/.local/share/rhythmbox/rhythmdb.xml', mode 'r' at 0x4809af98>
>>> iter(f)
<open file '/home/ulrik/.local/share/rhythmbox/rhythmdb.xml', mode 'r' at 0x4809af98>
>>> iter(f)
<open file '/home/ulrik/.local/share/rhythmbox/rhythmdb.xml', mode 'r' at 0x4809af98>
你看到的是每次调用ITER()的iterparse对象返回一个新的发电机。但是,该文件对象具有必须保留的内部操作系统状态,并且它具有自己的迭代器。
@kaizer:实际上,它就好像每次在for循环输入element.clear()之后处理文档的子集? – jldupont 2009-10-03 12:43:23
你还没有定义你想要做什么,你的期望让我感到惊讶;我将在整个文档中使用iterparse作为循环。我会举个例子。 – u0b34a0f6ae 2009-10-03 13:27:33
@kaizer:非常感谢您的所有努力。感谢这篇文章,我发现了SAX解析器,看起来我可以用这种方法整洁地构建基于状态机的解析器。 (你能告诉我我是一个XML新手?;-) – jldupont 2009-10-03 15:24:04
这是可能的ElementTree的和增量解析: http://effbot.org/zone/element-iterparse.htm#incremental-parsing
import xml.etree.cElementTree as etree
for event, elem in etree.iterparse(source):
...
更容易比SAX使用。
@jldupont:你的问题说你尝试过(两年前):“”“我试过”xml.etree.cElementTree“的iterparse(这真的很不错)”“” – 2012-01-01 22:16:38
-1 Large file means使用cElementTree(OP的状态已经被使用了!)...你没有阅读@ kaiser.se的答案吗? – 2012-01-01 22:18:52
这就是我想要的......我不介意对“开始标记”等事件做出“反应”。 – jldupont 2009-10-03 12:21:52
@ Jean-Lou:如果你不需要整棵树,那么SAX就是要走的路。它用于将文档处理为事件流而不是内容树。 – 2009-10-03 13:32:10