2012-10-09 11 views
18

私は、(1GBまで)十分な大きさのxml文書を処理し、それらをpythonで解析する必要があります。私はiterparse()関数(SAXスタイルの解析)を使用しています。ElementTree iterparse strategy

私の関心は以下の通りです

、あなたは私が(シンプソンズとして)ファミリ名を取得していますし、私は名前を取得していますときとき知っている問題は、もちろん、である。この

<?xml version="1.0" encoding="UTF-8" ?> 
<families> 
    <family> 
    <name>Simpson</name> 
    <members> 
     <name>Homer</name> 
     <name>Marge</name> 
     <name>Bart</name> 
    </members> 
    </family> 
    <family> 
    <name>Griffin</name> 
    <members> 
     <name>Peter</name> 
     <name>Brian</name> 
     <name>Meg</name> 
    </members> 
    </family> 
</families> 

のようなXMLを持っている想像その家族の一人(例えばホーマー)の

私がこれまで行ってきたことは、私が "members"タグの中にいるかどうかを教えてくれる "スイッチ"を使うことです。

import xml.etree.cElementTree as ET 

__author__ = 'moriano' 

file_path = "test.xml" 
context = ET.iterparse(file_path, events=("start", "end")) 

# turn it into an iterator 
context = iter(context) 
on_members_tag = False 
for event, elem in context: 
    tag = elem.tag 
    value = elem.text 
    if value : 
     value = value.encode('utf-8').strip() 

    if event == 'start' : 
     if tag == "members" : 
      on_members_tag = True 

     elif tag == 'name' : 
      if on_members_tag : 
       print "The member of the family is %s" % value 
      else : 
       print "The family is %s " % value 

    if event == 'end' and tag =='members' : 
     on_members_tag = False 
    elem.clear() 

、出力が

The family is Simpson 
The member of the family is Homer 
The member of the family is Marge 
The member of the family is Bart 
The family is Griffin 
The member of the family is Peter 
The member of the family is Brian 
The member of the family is Meg 

私の関心は私があったタグに知るために余分な変数を作成する必要がありました。この(簡単な)の例で(on_members_tag)真のXMLの例と想像していることであるので、これは正常に動作します私が処理しなければならないものは、より多くのネストされたタグを持っています。

これは非常に減らされた例であることに注意してください。私は、より多くのタグ、より多くの内部タグ、および異なるタグ名、属性などを取得しようとするXMLに直面していると仮定できます。

質問があります。恐ろしく愚かなことをやっていますか?私はこれにもっと洗練された解決策がなければならないように感じる。

+0

あなたがデータで何をしますか?すべてを保持するためのPythonデータ構造を構築するか、反復処理中にdbに格納するか、それとも何か他のもの? –

+0

@JanneKarila:データはpython構造体に置かれ、dbに保存されたり、ファイルにダンプされたりする可能性があります。この場合は、dbに書き込まれると仮定できます。 –

答えて

24

ここでは、可能なアプローチの1つがあります。パスリストを維持し、親ノードを見つけるために後方を見る。

path = [] 
for event, elem in ET.iterparse(file_path, events=("start", "end")): 
    if event == 'start': 
     path.append(elem.tag) 
    elif event == 'end': 
     # process the tag 
     if elem.tag == 'name': 
      if 'members' in path: 
       print 'member' 
      else: 
       print 'nonmember' 
     path.pop() 
+0

シンプルでエレガントで、 。ありがとうたくさん:) –

+0

このアプローチの標準的な名前はありますか?私はこのアプローチが多くのそのような問題に使われていると信じています。あなたがその名前を伝えることができれば、私はもっと深く掘り下げて理解することができます。 –

11

pulldomがこれに適しています。あなたはサックスのストリームを手に入れます。ストリームを反復することができます。関心のあるノードを見つけたら、そのノードをDOMフラグメントにロードします。

import xml.dom.pulldom as pulldom 
import xpath # from http://code.google.com/p/py-dom-xpath/ 

events = pulldom.parse('families.xml') 
for event, node in events: 
    if event == 'START_ELEMENT' and node.tagName=='family': 
     events.expandNode(node) # node now contains a dom fragment 
     family_name = xpath.findvalue('name', node) 
     members = xpath.findvalues('members/name', node) 
     print('family name: {0}, members: {1}'.format(family_name, members)) 

出力:

family name: Simpson, members: [u'Hommer', u'Marge', u'Bart'] 
family name: Griffin, members: [u'Peter', u'Brian', u'Meg'] 
+0

これは非常に素晴らしい解決策ですが、受け入れられた答えとして私はあなたにそれを与えることはできません(私はnneonneoの答えが良いのが好きです)。しかし、それは間違いなく洗練されたソリューションのように見えます。ありがとう! –

+0

偉大な答え。非常に使いやすい。 46 GB xmlファイルの解析を許可 –

関連する問題