我正在尝试解析一个大文件(> 2GB)的结构化标记数据,而内存还不足以满足这一要求。这就是XML解析类的最佳方式。更多细节请。
答案 0 :(得分:11)
查看iterparse()
功能。可以找到如何使用它来解析非常大的文档的说明here。
答案 1 :(得分:5)
大多数DOM库(如ElementTree)在核心中构建整个文档模型。传统上,当您的模型太大而无法同时适应内存时,您需要使用更加面向流的解析器,如xml.sax。
这通常比你预期的要困难,特别是当用于高阶操作时,比如一次处理整个DOM。
您的xml文档是否可能非常简单,如
<entries>
<entry>...</entry>
<entry>...</entry>
</entries>
这将允许您以更加ElementTree友好的方式处理数据的子集?
答案 2 :(得分:2)
我见过的唯一可以处理这类事情的API是pulldom:
http://docs.python.org/library/xml.dom.pulldom.html
Pulldom使用SAX API构建部分DOM节点;通过将特定的子树作为一个组拉入,然后在完成后丢弃它们,您可以通过使用DOM的合理性来获得SAX的内存效率。
这是一个不完整的API;当我使用它时,我必须修改它以使其完全可用,但它作为基础。我不再使用它,所以我不记得我必须添加的内容;只是提前警告。
这很慢。
XML是一种处理大型数据集的非常糟糕的格式。如果您对源数据有任何控制权,并且对数据集有意义,那么您最好将数据分成更小的块,以便可以完全解析为内存。
另一种选择是使用SAX API,但直接做任何不重要的事情都是一件非常痛苦的事。
答案 3 :(得分:1)
是的,十年后,已经有许多用于处理大文件的新解决方案。下面我为大家推荐一个。
例如,文件test.xml的内容如下
<?xml version="1.0" encoding="UTF-8"?>
<breakfast_menu>
<food>
<name>Strawberry Belgian Waffles</name>
<price>$7.95</price>
<description>
Light Belgian waffles covered with strawberries and whipped cream
</description>
<calories>900</calories>
</food>
<food>
<name>Berry-Berry Belgian Waffles</name>
<price>$8.95</price>
<description>
Belgian waffles covered with assorted fresh berries and whipped cream
</description>
<calories>900</calories>
</food>
......
</breakfast_menu>
使用SimplifiedDoc的解决方案如下:
from simplified_scrapy import SimplifiedDoc, utils
doc = SimplifiedDoc()
doc.loadFile('test.xml', lineByline=True)
for food in doc.getIterable('food'):
print (food.children.text)
结果:
['Strawberry Belgian Waffles', '$7.95', 'Light Belgian waffles covered with strawberries and whipped cream', '900']
...
答案 4 :(得分:0)
其他答复者告诉ElementTree
是DOM解析器,尽管它具有iterparse()方法。
为减少内存占用,我使用了真正的SAX解析器。 Here是我用于解决方案的链接。 Here's官方文档。这是我的XML:
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<entity storageTableName="table7113" tableName="TableBusinessName">
<attribute storageFieldName="field7114" fieldName="BusinessName1" />
<attribute storageFieldName="field7115" fieldName="BusinessName2" />
. . .
</entity>
. . .
</metadata>
这是代码:
import xml.sax
class ModelNameHandler(xml.sax.ContentHandler):
ENTITY_TAG = "entity"
STORAGE_TABLE_NAME_ATTR = "storageTableName"
TABLE_NAME_ATTR = "tableName"
ATTRIBUTE_TAG = "attribute"
STORAGE_FIELD_NAME_ATTR = "storageFieldName"
FIELD_NAME_ATTR = "fieldName"
def __init__(self):
self.entity_code = None
self.entity_names = {}
self.attr_names = {}
def startElement(self, tag, attributes):
if tag == self.ENTITY_TAG:
self.entity_code = attributes[self.STORAGE_TABLE_NAME_ATTR]
entity_name = attributes[self.TABLE_NAME_ATTR]
self.entity_names[self.entity_code] = entity_name
elif tag == self.ATTRIBUTE_TAG:
attr_code = attributes[self.STORAGE_FIELD_NAME_ATTR]
key = self.entity_code + "." + attr_code
attr_name = attributes[self.FIELD_NAME_ATTR]
self.attr_names[key] = attr_name
def get_model_names(file):
parser = xml.sax.make_parser()
parser.setFeature(xml.sax.handler.feature_namespaces, 0)
handler = ModelNameHandler()
parser.setContentHandler(handler)
parser.parse(file)
return handler.entity_names, handler.attr_names
工作足够快。
以防万一,更多细节:
import my_package as p
if __name__ == "__main__":
with open('<my_path>/<my_file>.xml', 'r', encoding='utf_8') as file:
entity_names, attr_names = p.get_model_names(file)