3

我正在尝试解析 xml。第一个 iterparse 工作正常,但第二个开始填充内存。如果删除第一个 iterparse,则没有任何变化。XML 是有效的。

def clear_element(e):
    e.clear()
    while e.getprevious() is not None:
        del e.getparent()[0]

def import_xml(request):
    f = 'file.xml'
    offers = etree.iterparse(f, events=('end',), tag='offer')
    for event, offer in offers:
        # processing
        # works correctly
        clear_element(offer)

    categories = etree.iterparse(f, events=('end',), tag='category')
    for event, category in categories:
        # using memory
        clear_element(category)

XML:

<shop>
    <categories>
        <category>name</category>
        <category>name</category>
        <category>name</category>
          ~ 1000 categories
    </categories>
    <offers>
        <offer>
           <inner_tag>data</inner_tag>
           <inner_tag>data</inner_tag>
        </offer>
        <offer>
           <inner_tag>data</inner_tag>
           <inner_tag>data</inner_tag>
        </offer>
          ~ 450000 offers
    </offers>
</shop>
4

2 回答 2

3

您要解析文件两次,第一次是保留所有category标签并删除offer标签,这对于 1000 个category标签不会占用太多内存。

但是第二次只删除category标签同时保留所有 450000个offer标签,这就是构建树需要大量内存的原因。

在这种情况下,最好不要使用tag参数iterparse并检查标记名,同时删除所有不需要的标记:

def import_xml(request):
    f = 'file.xml'
    elements = etree.iterparse(f, events=('end',))
    for event, element in elements:
        if element.tag == 'offer':
            # handle offer ...
        elif element.tag == 'category':
            # handle category ...
        else:
            continue
        element.clear()
        element.getparent().remove(element)

注意:只是调用element.clear()而不从父级删除它仍然会将清除的元素作为构造树的一部分留在内存中。可能clear真的不需要...

于 2014-10-17T23:20:52.970 回答
0

我也打iterparse了一段时间,现在终于认为我知道如何正确使用它了,所以这是我的智慧之言:使用时iterparse

  1. 确保使用cElementTree实现

  2. 确保清除沿途不需要的任何元素。如果您有一个非常复杂的具有深层嵌套结构的 XML,这一点尤其重要。

所以让我们假设你XML有这样的额外节点:

<offers>
    <offer>
       <inner_tag>data</inner_tag>
              <i2>
                    <i3>1000 characters of something</i3>                       
             </i2>
       <inner_tag>data</inner_tag>
    </offer>
</offers>

那么您的代码应如下所示:

def import_xml(request):
f = 'file.xml'
elements = etree.iterparse(f, events=('end',))
for event, element in elements:
    if element.tag == 'offer':
        # handle offer ...
    elif element.tag == 'category':
        # handle category ...
    elif element.tag != 'i2':
        continue
    element.clear()

这样,您将省略完整的<i2>节点及其内容,同时能够处理其中的任何其他元素<offers>

element.getparent().remove(element)在我的代码中不起作用(AttributeError)。

于 2015-11-18T08:17:59.270 回答