2011-01-18 9 views
4

ElementTree for Python(2.6)の標準実装では、子ノードからの親へのポインタは提供されません。したがって、両親が必要な場合は、子どもではなく親をループすることが推奨されます。Pythonを使用して複数の(親、子)ノードを反復するElementTree

私の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)のような、しかし親情報と(おそらく)同じ結果を達成するために、条件付きDが追加:

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

ElementTree documentation getiterator()メソッドは、深さ優先探索を行うことを示唆しています。親(1)利回りを探しせずにそれを実行:

first 
second 
third 

はしかし、(3)でパラスからテキストを抽出し、利回り:

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

これは、幅優先ように見えます。

したがって、2つの質問が発生します。

  1. これは間違いありませんか?
  2. 子が特定のタイプでなければならないが、親が何でもかまいません()場合、どのように(親、子)タプルを抽出しますか?。私は2つのループを実行し、(3)で生成された(親、子)を(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"要素から興味のある要素を抜き出しています。

>>> 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 
>>> 

は今、あなたは、彼らが過去をストリームとしてその親への参照(もしあれば)と「パラ」の要素それぞれをSNARFことができます。

一つの解決策は、あなた自身の反復を行うことです。

これは、発電機のガジェットにきれいにラップすることができます。

>>> 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 
>>> 
+0

は、このソリューションをありがとうございました。 =) – mmmdreg