4

ElementTree for Python(2.6)の標準実装では、子ノードから親へのポインターは提供されません。したがって、親が必要な場合は、子ではなく親をループすることをお勧めします。

私のxmlが次の形式であると考えてください。

<Content>
  <Para>first</Para>
  <Table><Para>second</Para></Table>
  <Para>third</Para>
</Content>

以下は、親を考慮せずにすべての「パラ」ノードを検索します。

(1) paras = [p for p in page.getiterator("Para")]

これ(effbotから採用)は、子ノードの代わりにループすることで親を格納します。

(2) paras = [(c,p) for p in page.getiterator() for c in p]

これは完全に理にかなっており、条件付きで拡張して(おそらく)(1)と同じ結果を達成できますが、親情報を追加します。

(3) paras = [(c,p) for p in page.getiterator() for c in p if c.tag == "Para"]

ElementTreeのドキュメントでは、getiterator()メソッドが深さ優先探索を実行することを提案しています。親(1)を検索せずに実行すると、次のようになります。

first
second
third

ただし、(3)のパラグラフからテキストを抽出すると、次のようになります。

first, Content>Para
third, Content>Para
second, Table>Para

これは幅優先のようです。

したがって、これは2つの疑問を提起します。

  1. これは正しく、期待される動作ですか?
  2. 子が特定のタイプである必要があるが、ドキュメントの順序を維持する必要がある場合、親は何でもかまいませんが、(親、子)タプルをどのように抽出しますか。2つのループを実行し、(3)によって生成された(親、子)を(1)によって生成された順序にマッピングすることは理想的ではないと思います。
4

1 に答える 1

5

このことを考慮:

>>> xml = """<Content>
...   <Para>first</Para>
...   <Table><Para>second</Para></Table>
...   <Para>third</Para>
... </Content>"""
>>> import xml.etree.cElementTree as et
>>> page = et.fromstring(xml)
>>> for p in page.getiterator():
...     print "ppp", p.tag, repr(p.text)
...     for c in p:
...         print "ccc", c.tag, repr(c.text), p.tag
...
ppp Content '\n  '
ccc Para 'first' Content
ccc Table None Content
ccc Para 'third' Content
ppp Para 'first'
ppp Table None
ccc Para 'second' Table
ppp Para 'second'
ppp Para 'third'
>>> 

余談ですが、リスト内包表記は、何が繰り返されているかを正確に確認したいまでは素晴らしいものです:-)

getiterator アドバタイズされた順序で「ppp」要素を生成していますただし、目的の順序にない補助的な「ccc」要素から関心のある要素を抽出しています。

1つの解決策は、独自の反復を行うことです。

>>> def process(elem, parent):
...    print elem.tag, repr(elem.text), parent.tag if parent is not None else None
...    for child in elem:
...       process(child, elem)
...
>>> process(page, None)
Content '\n  ' None
Para 'first' Content
Table None Content
Para 'second' Table
Para 'third' Content
>>>

これで、「Para」要素を、それらが通過するときにその親(存在する場合)への参照を使用してスナフすることができます。

これは、ジェネレーターガジェットでうまくまとめることができます。

>>> def iterate_with_parent(elem):
...     stack = []
...     while 1:
...         for child in reversed(elem):
...             stack.append((child, elem))
...         if not stack: return
...         elem, parent = stack.pop()
...         yield elem, parent
...
>>>
>>> showtag = lambda e: e.tag if e is not None else None
>>> showtext = lambda e: repr((e.text or '').rstrip())
>>> for e, p in iterate_with_parent(page):
...     print e.tag, showtext(e), showtag(p)
...
Para 'first' Content
Table '' Content
Para 'second' Table
Para 'third' Content
>>>
于 2011-01-18T07:25:15.893 に答える