有时咱们须要的只是树内某个地方的一小部分,所以将整个树解析到内存中,全体遍历并进行相关操做形成的内存开销会很大
所以,etree提供了两个事件驱动的解析器接口
一个是在构建树时,生成解析器事件(iterparse)
另外一个根本不构建树,而是以相似SAX的方式调用目标对象的反馈方法数据库
some_file_like = BytesIO(b"<root><a>data</a></root>") for event, element in etree.iterparse(some_file_like): print("%s, %4s, %s" % (event, element.tag, element.text) ''' 输出: end, a, data end, root, None '''
默认状况下,iterparse()只在解析完元素时生成事件,但能够经过events关键字参数控制app
some_file_like = BytesIO(b"<root><a>data</a></root>") for event, element in etree.iterparse(some_file_like,events=("start", "end")): print("%5s, %4s, %s" % (event, element.tag, element.text)) ''' 输出: start, root, None start, a, data end, a, data end, root, None '''
注意,在接收开始事件时,元素的文本、尾部和子元素还不必定存在,只有结束事件才能保证元素已被彻底解析
它还容许您.clear()或修改元素的内容以节省内存
所以,若是您解析一个大的树而且但愿保持内存使用量小,那么您应该清理树中再也不须要的部分
.clear()的keep_tail=True参数确保当前元素后面的(tail)文本内容不会被触摸
强烈建议修改解析器可能还没有彻底读取的任何内容spa
some_file_like = BytesIO(b"<root><a><b>data</b></a><a><b/></a></root>") for event, element in etree.iterparse(some_file_like): if element.tag == 'b': print(element.text) elif element.tag == 'a': print("** cleaning up the subtree") element.clear(keep_tail=True) ''' 输出: data ** cleaning up the subtree None ** cleaning up the subtree '''
iterparse()的一个很是重要的用例是解析生成的大型XML文件,例如数据库转储
大多数状况下,这些XML格式只有一个主数据项元素挂在根节点的正下方,而且重复了数千次
在这种状况下,最好让lxml.etree来构建树,而且只截取这一个元素,使用普通的树API来提取数据code
xml_file = BytesIO(b'''\ <root> <a><b>ABC</b><c>abc</c></a> <a><b>MORE DATA</b><c>more data</c></a> <a><b>XYZ</b><c>xyz</c></a> </root>''') for _, element in etree.iterparse(xml_file, tag='a'): print('%s -- %s' % (element.findtext('b'), element[1].text)) element.clear(keep_tail=True) ''' 输出: ABC -- abc MORE DATA -- more data XYZ -- xyz '''
若是出于某种缘由根本不须要构建树,则可使用lxml.etree的目标解析器接口
它经过调用目标对象的方法建立相似SAX的事件。经过实现部分或所有这些方法,能够控制生成哪些事件xml
class ParserTarget: events = [] close_count = 0 def start(self, tag, attrib): self.events.append(("start", tag, attrib)) def close(self): events, self.events = self.events, [] self.close_count += 1 return events parser_target = ParserTarget() parser = etree.XMLParser(target=parser_target) events = etree.fromstring('<root test="true"/>', parser) print(parser_target.close_count) #输出:1 for event in events: print('event: %s - tag: %s' % (event[0], event[1])) for attr, value in event[2].items(): print(' * %s = %s' % (attr, value)) ''' 输出: event: start - tag: root * test = true '''
可随时重用解析器及其目标,所以要确保.close()方法确实已将目标状态重置为可用(在出现错误时也是如此!)对象
events = etree.fromstring('<root test="true"/>', parser) print(parser_target.close_count) #输出:2 events = etree.fromstring('<root test="true"/>', parser) print(parser_target.close_count) #输出:3 events = etree.fromstring('<root test="true"/>', parser) print(parser_target.close_count) #输出:4 for event in events: print('event: %s - tag: %s' % (event[0], event[1])) for attr, value in event[2].items(): print(' * %s = %s' % (attr, value)) ''' 输出: event: start - tag: root * test = true '''