我需要处理一个大约 8Gb 的大 .XML 文件。文件结构(简化)类似于以下内容:
<TopLevelElement>
<SomeElementList>
<Element>zzz</Element>
....and so on for thousands of rows
</SomeElementList>
<Records>
<RecordType1>
<RecordItem id="aaaa">
<SomeData>
<SomeMoreData NameType="xxx">
<NameComponent1>zzz</NameComponent1>
....
<AnotherNameComponent>zzzz</AnotherNameComponent>
</SomeMoreData>
</SomeData>
</RecordItem>
..... hundreds of thousands of items, some are quite large.
</RecordType1>
<RecordType2>
<RecordItem id="cccc">
...hundreds of thousands of RecordType2 elements, slightly different from RecordItems in RecordType1
</RecordItem>
</RecordType2>
</Records>
</TopLevelElement>
我需要提取 RecordType1 和 RecordType2 元素中的一些子元素。有条件决定哪些记录项需要处理,哪些字段需要提取。单个 RecordItems 不超过 120k(有些有大量文本数据,我不需要)。
这是代码。函数 get_all_records 接收以下输入: a) XML 文件的路径;b) 记录类别(“RecordType1”或“RecordType2”);c) 选择什么名称组件
from xml.etree import cElementTree as ET
def get_all_records(xml_file_path, record_category, name_types, name_components):
context = ET.iterparse(xml_file_path, events=("start", "end"))
context = iter(context)
event, root = next(context)
all_records = []
for event, elem in context:
if event == 'end' and elem.tag == record_category and elem.attrib['action'] != 'del':
record_contents = get_record(elem, name_types=name_types, name_components=name_components, record_id=elem.attrib['id'])
if record_contents:
all_records += record_contents
root.clear()
return all_records
我已经尝试过记录的数量,代码在大约一分钟内很好地处理了 100k RecordItems(仅 Type1,到达 Type2 需要太长时间)。试图处理更多的记录(我拿了一百万),最终导致 ElementTree.py 中的 MemoryError。所以我猜尽管有 root.clear() 声明,但没有释放内存。
一个理想的解决方案是一次读取一个 RecordItems,进行处理,然后从内存中丢弃,但我不知道如何做到这一点。从 XML 的角度来看,两个额外的元素层(TopLevelElement 和 Records)似乎使任务复杂化。我是 XML 和相应 Python 库的新手,因此非常感谢详细解释!