2013-05-23 1 views
3

Я использую lxml.iterparse для синтаксического анализа довольно большого xml-файла. В определенный момент генерируется исключение из памяти. Я знаю о похожих вопросах и что есть дерево, которое вы должны нормально очистить с помощью element.clear(), когда вы больше не используете его.lxml element.clear() и access childelements

Мой код выглядит следующим образом (укороченный):

for event,element in context : 
    if element.tag == xmlns + 'initialized':   
     attributes = element.findall(xmlns+'attribute')   
     heapsize = filter(lambda x:x.attrib['name']=='maxHeapSize', attributes)[0].attrib['value'] 
     characteristics['max_heap_size_MB'] = bytes_to_MB(int(heapsize, 16)) 

    #clear up the built tree to avoid mem alloc fails 
    element.clear() 
del context 

Это работает, если я закомментировать element.clear(). Если я использую element.clear я получаю Keyerrors как это:

Traceback (most recent call last): 
    File "C:\Users\NN\Documents\scripts\analyse\analyse_all.py", line 289, in <module> 
    main() 
    File "C:\Users\NN\Documents\scripts\analyse\analyse_all.py", line 277, in main 
    join_characteristics_and_score(logpath, benchmarkscores) 
    File "C:\Users\NN\Documents\scripts\analyse\analyse_all.py", line 140, in join_characteristics_and_score 
    parsed_verbose_xml = parse_xml(verbose) 
    File "C:\Users\NN\Documents\scripts\analyse\analyze_g.py", line 62, in parse_xml 
    heapsize = filter(lambda x:x.attrib['name']=='maxHeapSize', attributes)[0].attrib['value'] 
    File "C:\Users\NN\Documents\scripts\analyse\analyze_g.py", line 62, in <lambda> 
    heapsize = filter(lambda x:x.attrib['name']=='maxHeapSize', attributes)[0].attrib['value'] 
    File "lxml.etree.pyx", line 2272, in lxml.etree._Attrib.__getitem__ (src\lxml\lxml.etree.c:54751) 
KeyError: 'name' 

Когда я печать элементов они являются обычной dicts со значениями в них без использования element.clear(). При очистке эти dicts пусты.

EDIT

минимальный ход питон программа, иллюстрирующая проблема:

#!/usr/bin/python 

from lxml import etree 
from pprint import pprint 

def fast_iter(context, func, *args, **kwargs): 
     # http://www.ibm.com/developerworks/xml/library/x-hiperfparse/ 
     # Author: Liza Daly 
     for event, elem in context: 
      func(elem, *args, **kwargs) 
      elem.clear() 
      while elem.getprevious() is not None: 
       del elem.getparent()[0] 
     del context 

def process_element(elem): 
     xmlns = "{http://www.ibm.com/j9/verbosegc}" 

     if elem.tag == xmlns + "gc-start": 
      memelements = elem.findall('.//root:mem', namespaces = {'root':xmlns[1:-1]}) 
      pprint(memelements) 

if __name__ == '__main__': 
    with open('small.xml', "r+") as xmlf: 
       context = etree.iterparse(xmlf) 
       fast_iter(context, process_element) 

Содержания XML файл выглядит следующим образом:

<verbosegc xmlns="http://www.ibm.com/j9/verbosegc"> 
<gc-start id="5" type="scavenge" contextid="4" timestamp="2013-06-14T15:48:46.815"> 
    <mem-info id="6" free="3048240" total="4194304" percent="72"> 
    <mem type="nursery" free="0" total="1048576" percent="0"> 
     <mem type="allocate" free="0" total="524288" percent="0" /> 
     <mem type="survivor" free="0" total="524288" percent="0" /> 
    </mem> 
    <mem type="tenure" free="3048240" total="3145728" percent="96"> 
     <mem type="soa" free="2891568" total="2989056" percent="96" /> 
     <mem type="loa" free="156672" total="156672" percent="100" /> 
    </mem> 
    <remembered-set count="1593" /> 
    </mem-info> 
</gc-start> 
</verbosegc> 
+0

Как он «ломается»? – Blender

+0

Почему бы не использовать 'element.findall ('{% s} атрибут'% xmlns)' вместо? Не нужно перебирать все подэлементы. –

+0

@blender: я получаю keyerror при попытке получить доступ к определенным атрибутам, выполнив: child.attrib ['key']. без очистки этих работ – Nicolas

ответ

3

Лиза Дейли написали большую статью около processing large XML using lxml. Попробуйте представленный здесь код fast_iter:

import lxml.etree as ET 
import pprint 


def fast_iter(context, func, *args, **kwargs): 
    """ 
    http://www.ibm.com/developerworks/xml/library/x-hiperfparse/ (Liza Daly) 
    See also http://effbot.org/zone/element-iterparse.htm 
    """ 
    for event, elem in context: 
     func(elem, *args, **kwargs) 
     # It's safe to call clear() here because no descendants will be 
     # accessed 
     elem.clear() 
     # Also eliminate now-empty references from the root node to elem 
     # (ancestor loop added by unutbu) 
     for ancestor in elem.xpath('ancestor-or-self::*'): 
      while ancestor.getprevious() is not None: 
       del ancestor.getparent()[0] 
    del context 


def process_element(elem, namespaces): 
    memelements = elem.findall('.//root:mem', namespaces=namespaces) 
    pprint.pprint(memelements) 

if __name__ == '__main__': 
    xmlns = "http://www.ibm.com/j9/verbosegc" 
    namespaces = {'root': xmlns} 
    with open('small.xml', "r+") as xmlf: 
     context = ET.iterparse(xmlf, events=('end',), 
           tag='{{{}}}gc-start'.format(xmlns)) 
     fast_iter(context, process_element, namespaces) 
+0

Я надеялся, что есть решение, которое на самом деле не требует перезаписывания моего кода. – Nicolas

+0

Я пробовал переписывать код, но я сталкиваюсь в основном с той же проблемой: если я попытаюсь выполнить element.findall внутри метода process(), он возвращает пустой список , а без очистки я получаю желаемых детей. – Nicolas

+0

Пожалуйста, отправьте примерный пример с образцом XML, который демонстрирует проблему. – unutbu

Смежные вопросы