0

チュートリアルの「イベント駆動型解析」セクションで説明されているパターンを使用しようとしています。lxml

私のコードでは、iterchildren()メソッドを使用して要素に対して再帰的に実行できる関数を呼び出しています。ここでは、例として 2 つのネストされたループを使用します。

これは期待どおりに機能します。

xml = StringIO("<root><a><b>data</b><c><d/></c></a><a><z/></a></root>")
for ev, elem in etree.iterparse(xml):
    if elem.tag == 'a':
        for c in elem.iterchildren():
             for gc in c.iterchildren():
                  print gc

出力は<Element d at 0x2df49b0>です。

しかし.clear()、最後に追加すると:

for ev, elem in etree.iterparse(xml):
    if elem.tag == 'a':
        for c in elem.iterchildren():
             for gc in c.iterchildren():
                  print gc
    elem.clear()

-- 何も印刷されません。なぜそうなるのですか? また、これを回避するにはどうすればよいですか?

ノート:

  • スキップiterchildrenして、for c in elemまたはを実行for c in list(elem)しても、同じ効果があります。
  • メモリ使用量を低く抑えるには、反復アプローチを使用する必要があります。
  • 実際の使用例では、属性を使用して要素の検索を行っています。

    if elem.attrib.get('id') == elem_id:
        return _get_info(elem)
    

内部要素が処理される前に消去する方法clearと、先祖の処理に必要な間、それらをメモリに保持する方法について説明してください。

4

1 に答える 1

2

問題は、iterparseデフォルトでendイベントが発生することです。サブ要素endのイベントは、祖先よりも早く生成されます。

>>> for ev, elem in etree.iterparse(xml):
       print elem

<Element b at 0x38fe320>
<Element d at 0x38fe0f0>
<Element c at 0x38fe2d0>
<Element a at 0x38fe190>
<Element z at 0x38fe230>
<Element a at 0x38fe3c0>
<Element root at 0x2df48c0>

startこの単純なケースでは、代わりにイベントに依存することで問題を解決できます。

for ev, elem in etree.iterparse(xml, events=('start',)):
    ...

ただし、リンクされたドキュメントによると、

Element のテキスト、末尾、および子は、開始イベントを受け取った時点でまだそこにあるとは限らないことに注意してください。Element が完全に解析されたことを保証するのは end イベントだけです。

これはおそらく、startendイベントの両方を処理して、安全な場合にのみ呼び出しを許可する必要があることを意味しclear()ます。ある種のスタックを実装し、そこにイベントをプッシュし、startイベントをポップしてclearing することを考えていend ます。

これまたは他のアイデアを使用した実装を示す回答を大歓迎します。

: 最も簡単な方法は、clear呼び出しを.xml にインデントすることifです。これにより、孫へのアクセスは許可されますが、関連のない要素はすべて uned のままになりclearます。


編集

現在、次の方法で状態保持変数を使用しています。

found = False
for event, elem in etree.iterparse(source, events=('start', 'end')):
    if event == 'start':
        if elem.attrib.get('id') == elem_id:
            found = True
    else:
        if elem.attrib.get('id') == elem_id:
            return _get_info(elem)
        if not found:
            elem.clear()
于 2012-09-11T12:35:01.263 に答える