非常に大きなXMLファイル(3〜5 GBの範囲)を解析する必要があります。これは、XMLノードに含まれるデータに従っていくつかの小さなXMLファイルに分割する必要があります。
<measure>
この(非常に)単純化されたフラグメントのように、各入力ファイルには数十万の要素が含まれています。
<items>
<measure code="0810">
<condition sequ="001" SID="-5041162"/>
<footnote Id="00550"/>
<footnote Id="00735"/>
</measure>
<measure code="6304">
<component Id="01" national="1"/>
<footnote Id="00001"/>
</measure>
<measure code="0811">
<condition sequ="002" SID="-5041356"/>
<footnote Id="00555"/>
</measure>
<measure code="2915">
<component Id="01" national="0"/>
<certif SID="-737740"/>
<certif SID="-737780"/>
</measure>
</items>
実際の<measure>
要素のコンテンツは、ほとんどすべての整形式XMLにすることができます。
これらのファイルを解析するときに、2つのプロセスを実行する必要があります。
<measure>
要素のコンテンツから情報を抽出し、MongoDBデータベースにダンプします(この部分は解決されています...)<measure>
ノードの「コード」属性の最初の2桁に基づいて、元のXMLファイルをたとえば100個のXMLサブファイルに分割します。つまり、新しい100個のXMLファイル(「part_00.xml」から「part_99.xml」という名前)を作成し、各<measure>
要素を対応するサブファイルに追加する必要があります。すなわち、<measure>
試料内のブロック1及び3「part_08.xml」にコピーする必要があり、ブロック2「part_63.xml」にコピーされなければなりません...SAXを使用して元のファイルを解析していますが、上記のプロセス1は正常に実行されます。SAXプロセスの純粋なスケルトンは次のとおりです。
import sys
from xml.sax import ContentHandler
from xml.sax import make_parser
class ParseMeasures(ContentHandler):
code = ''
def startElement(self, name, attrs):
if name == 'measure':
self.code = attrs.get('code')
def endElement(self, name):
if name == 'measure':
print('***Must append <measure> block to file part_{0}.xml'.format(self.code[:2]))
def main(args):
handler = ParseMeasures()
sax_parser = make_parser()
sax_parser.setContentHandler(handler)
sax_parser.parse('my_large_xml.file.xml')
print('Ended')
if __name__ == '__main__':
main(sys.argv[1:])
必要なのは<measure>
、「endElement()」でXML要素全体にアクセスして、対応するサブファイルに追加できるようにすることです。
SAXを他のXML解析機能と組み合わせて<measure>
、「endElement()」でXML要素全体を取得できるようにする方法はありますか?(サブファイルの作成と管理を処理できます...これは問題ではありません!)
それとも、そもそもこの状況ではSAXアプローチが最適ではないのでしょうか。
「唯一の」警告は、プロセスが3〜5GBの範囲の入力ファイルを処理する必要があるということです。
以下は、組み込みのSAXパーサーを使用して解析イベントを生成し、lxmlを使用して部分ツリー(<measure>
要素のみ、一度に1つのみ)を構築するハイブリッドソリューションです。
要素が構築されると、lxmlのAPIによってシリアル化され、の値に応じて、増分XMLをさまざまなファイルに生成します@code
。
このコードは、<measure>
要素内のあらゆるレベルのネスト、および空白を含むテキスト値を処理します。現在、コメント、処理命令、または名前空間は処理されませんが、それらのサポートが追加される可能性があります。
入力ファイルが大きい場合でも、メモリ消費量は低く抑える必要があります。lxmlはオーバーヘッドを追加しますが、反復書き込みサポートは非常に便利です。これを完全に手動で行うと、全体的に高速になりますが、より複雑になります。
from xml.sax import ContentHandler, make_parser
from lxml import etree
class ParseMeasures(ContentHandler):
def __init__(self):
self.stack = []
self.open = False
self.elem = None
self.writers = {}
self.text = []
def _get_writer(self, filename):
with etree.xmlfile(filename) as xf:
with xf.element('items'):
while True:
el = (yield)
xf.write(el)
xf.flush() # maybe don't flush *every* write
def _write(self):
grp = self.elem.attrib['code'][0:2]
if grp in self.writers:
writer = self.writers[grp]
else:
writer = self.writers[grp] = self._get_writer('part_%s.xml' % grp)
next(writer) # run up to `yield` and wait
writer.send(self.elem) # write out current `<measure>`
self.elem = None
def _add_text(self):
if self.elem is not None and self.text:
if self.open:
self.elem.text = ''.join(self.text)
else:
self.elem.tail = ''.join(self.text)
self.text = []
def startElement(self, name, attrib):
if self.stack or name == 'measure':
self._add_text()
self.open = True
self.elem = etree.Element(name, attrib)
self.stack.append(self.elem)
if len(self.stack) > 1:
self.stack[-2].append(self.elem)
def characters(self, content):
if self.elem is not None:
self.text.append(content)
def endElement(self, name):
if self.stack:
self._add_text()
self.open = False
self.elem = self.stack.pop()
if not self.stack:
self._write()
def endDocument(self):
# clean up
for writer in self.writers:
self.writers[writer].close()
def main():
sax_parser = make_parser()
sax_parser.setContentHandler(ParseMeasures())
sax_parser.parse(r'test.xml')
if __name__ == '__main__':
main()
これにより、 part_08.xml
<items>
<measure code="0810">
<condition sequ="001" SID="-5041162"/>
<footnote Id="00550"/>
<footnote Id="00735"/>
</measure>
<measure code="0811">
<condition sequ="002" SID="-5041356"/>
<footnote Id="00555"/>
</measure>
</items>
そして part_29.xml
<items>
<measure code="2915">
<component Id="01" national="0"/>
<certif SID="-737740"/>
<certif SID="-737780"/>
</measure>
</items>
そして part_63.xml
<items>
<measure code="6304">
<component Id="01" national="1"/>
<footnote Id="00001"/>
</measure>
</items>
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加