什么是在Python中分析大型XML文档的最快方法?
我目前是基于Python Cookbook第12.5章的以下代码:
from xml.parsers import expat class Element(object): def __init__(self, name, attributes): self.name = name self.attributes = attributes self.cdata = '' self.children = [] def addChild(self, element): self.children.append(element) def getAttribute(self,key): return self.attributes.get(key) def getData(self): return self.cdata def getElements(self, name=''): if name: return [c for c in self.children if c.name == name] else: return list(self.children) class Xml2Obj(object): def __init__(self): self.root = None self.nodeStack = [] def StartElement(self, name, attributes): element = Element(name.encode(), attributes) if self.nodeStack: parent = self.nodeStack[-1] parent.addChild(element) else: self.root = element self.nodeStack.append(element) def EndElement(self, name): self.nodeStack.pop() def CharacterData(self,data): if data.strip(): data = data.encode() element = self.nodeStack[-1] element.cdata += data def Parse(self, filename): Parser = expat.ParserCreate() Parser.StartElementHandler = self.StartElement Parser.EndElementHandler = self.EndElement Parser.CharacterDataHandler = self.CharacterData ParserStatus = Parser.Parse(open(filename).read(),1) return self.root
我正在处理大小约1 GB的XML文档。 有谁知道一个更快的方法来parsing这些?
我看着我,就好像你不需要程序中的任何DOMfunction。 我会第二次使用(c)ElementTree库。 如果使用cElementTree模块的iterparse函数,则可以通过xml工作,并在事件发生时处理这些事件。
请注意,Fredriks使用cElementTree iterparse函数的build议:
为了parsing大文件,你可以在处理完它们之后马上删除元素:
for event, elem in iterparse(source): if elem.tag == "record": ... process record elements ... elem.clear()
上述模式有一个缺点, 它没有清除根元素,所以你将会得到一个有很多空子元素的元素。 如果你的文件很大,而不是很大,这可能是一个问题。 要解决这个问题,你需要把你的手放在根元素上。 最简单的方法是启用启动事件,并保存对variables中第一个元素的引用:
# get an iterable context = iterparse(source, events=("start", "end")) # turn it into an iterator context = iter(context) # get the root element event, root = context.next() for event, elem in context: if event == "end" and elem.tag == "record": ... process record elements ... root.clear()
lxml.iterparse()不允许这样做。
你有没有试过cElementTree模块?
Python 2.5及更高版本包含cElementTree,如xml.etree.cElementTree。 参考基准 。
删除了死的ImageShack链接
我build议你使用lxml ,它是libxml2库的一个python绑定,它非常快。
根据我的经验,libxml2和expat具有非常相似的性能。 但我更喜欢libxml2(和Python的lxml),因为它似乎更积极的开发和testing。 另外libxml2有更多的function。
lxml大部分与xml.etree.ElementTree兼容。 网站上有很好的文档。
如果您的应用程序对性能敏感,并且可能遇到大文件(如您所说,> 1GB),那么我强烈build议不要使用您在问题中显示的代码,原因很简单,因为它将整个文档加载到RAM 。 我鼓励你重新思考你的devise(如果可能的话),以避免一次把整个文档树保存在RAM中。 不知道你的应用程序的要求是什么,我不能正确地提出任何具体的方法,除了尝试使用“基于事件的”devise的通用build议。
注册callback会极大地降低parsing速度。 [编辑]这是因为(快速)的C代码必须调用python解释器,它不如C快。基本上,你使用C代码来读取文件(快速),然后在Python中构buildDOM (缓动)。[/编辑]
尝试使用在C中实现的xml.etree.ElementTree,它可以parsingXML,而不用任何callback到python代码。
文件parsing后,您可以过滤它,以得到你想要的。
如果这仍然太慢,你不需要一个DOM另一种select是将文件读取到一个string,并使用简单的string操作来处理它。
expat如果你不需要将整个树存储在内存中,那么ParseFile就可以很好的工作,
import xml.parsers.expat parser = xml.parsers.expat.ParserCreate() parser.ParseFile(open('path.xml', 'r'))
它将文件读入块,并将它们馈送到parsing器而不会使RAM爆炸。
Doc: https : //docs.python.org/2/library/pyexpat.html#xml.parsers.expat.xmlparser.ParseFile
显然PyRXP真的很快。
他们声称这是最快的parsing器 – 但cElementTree不在他们的统计列表中。