lxml iterparse mising дочерние узлы - PullRequest
2 голосов
/ 15 ноября 2011

Я использую lxml iterparse для чтения огромных XML-файлов. Для данного mainElement я проверяю дочерние элементы и обрабатываю каждый дочерний элемент. Но я заметил, что при проверке дочерних элементов в элементе анализатор иногда пропускает некоторые дочерние узлы. Я даже напечатал длину каждого элемента, которая должна быть постоянным числом для данного тега элемента, но иногда она меньше, чем должна быть. И, что удивительно, это обычно происходит в течение 5-го блока (один блок => mainElement вхождение). Есть ли причина, по которой парсер должен пропустить дочерние узлы? Любые подсказки?

Пример кода-

from lxml import etree  
def parseXml(context,attribList,elemList,mainElement):      
   for event, element in context: 
       if element.tag == mainElement and event=='start':
            for child in element:
               if child.tag in elemList:
                   print len(child) #for a given child,the len should be constant
                   #do things   
       elif event=='end':
         element.clear() 

Спасибо!

1 Ответ

2 голосов
/ 15 ноября 2011

Когда вы определяете контекст, обязательно установите для параметра events значение ('end',) вместо ('start',). В противном случае вы можете получить описание поведения, которое вы описываете.

context=etree.iterparse(filehandle, events=('end',), tag=mainElement)

Я думаю, что проблема в том, что lxml обрабатывает XML в одном потоке при выполнении parseXml в другом, поэтому вы можете получить элемент start в parseXml до того, как lxml выполнит синтаксический анализ соответствующего элемента end , Поэтому, когда вы перебираете дочерние элементы элемента, вы получаете только частичный результат.


Кстати, эта статья дает хороший способ организовать это, предназначенный для обработки очень больших XML:

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 parseXml(element,attribList,elemList): 
    for child in element:
       if child.tag in elemList:
           print len(child) #for a given child,the len should be constant
           #do things   

context=etree.iterparse(filehandle, events=('end',), tag=mainElement)   
fast_iter(context, parseXml, attribList, elemList)
...