XML ドキュメントを解析する¶
解析された XML ドキュメントは、XML ドキュメントのノードをネストさせる方法に基づいてツリー構造に関連付けた ElementTree と Element オブジェクトによってインメモリで表されます。
ドキュメント全体を解析する¶
ドキュメント全体を parse() で解析すると ElementTree インスタンスが返されます。このツリーは入力ドキュメントの全てのデータを解釈して、ツリーのノードは適切な位置で検索や操作ができます。この柔軟性は解析されたドキュメントをちょっと扱うには簡単ですが、ドキュメント全体を一度に読み込む必要があるので、イベントベースの解析方法よりも普通はより多くのメモリを使用します。
OPML アウトラインとして表されるポッドキャストのリストをサンプルに、シンプルなドキュメントでは、メモリ使用量は少なくて重要ではありません。
<?xml version="1.0" encoding="UTF-8"?>
<opml version="1.0">
<head>
<title>My Podcasts</title>
<dateCreated>Sun, 07 Mar 2010 15:53:26 GMT</dateCreated>
<dateModified>Sun, 07 Mar 2010 15:53:26 GMT</dateModified>
</head>
<body>
<outline text="Science and Tech">
<outline text="APM: Future Tense" type="rss"
xmlUrl="http://www.publicradio.org/columns/futuretense/podcast.xml"
htmlUrl="http://www.publicradio.org/columns/futuretense/" />
<outline text="Engines Of Our Ingenuity Podcast" type="rss"
xmlUrl="http://www.npr.org/rss/podcast.php?id=510030"
htmlUrl="http://www.uh.edu/engines/engines.htm" />
<outline text="Science & the City" type="rss"
xmlUrl="http://www.nyas.org/Podcasts/Atom.axd"
htmlUrl="http://www.nyas.org/WhatWeDo/SciencetheCity.aspx" />
</outline>
<outline text="Books and Fiction">
<outline text="Podiobooker" type="rss"
xmlUrl="http://feeds.feedburner.com/podiobooks"
htmlUrl="http://www.podiobooks.com/blog" />
<outline text="The Drabblecast" type="rss"
xmlUrl="http://web.me.com/normsherman/Site/Podcast/rss.xml"
htmlUrl="http://web.me.com/normsherman/Site/Podcast/Podcast.html" />
<outline text="tor.com / category / tordotstories" type="rss"
xmlUrl="http://www.tor.com/rss/category/TorDotStories"
htmlUrl="http://www.tor.com/" />
</outline>
<outline text="Computers and Programming">
<outline text="MacBreak Weekly" type="rss"
xmlUrl="http://leo.am/podcasts/mbw"
htmlUrl="http://twit.tv/mbw" />
<outline text="FLOSS Weekly" type="rss"
xmlUrl="http://leo.am/podcasts/floss"
htmlUrl="http://twit.tv" />
<outline text="Core Intuition" type="rss"
xmlUrl="http://www.coreint.org/podcast.xml"
htmlUrl="http://www.coreint.org/" />
</outline>
<outline text="Python">
<outline text="PyCon Podcast" type="rss"
xmlUrl="http://advocacy.python.org/podcasts/pycon.rss"
htmlUrl="http://advocacy.python.org/podcasts/" />
<outline text="A Little Bit of Python" type="rss"
xmlUrl="http://advocacy.python.org/podcasts/littlebit.rss"
htmlUrl="http://advocacy.python.org/podcasts/" />
<outline text="Django Dose Everything Feed" type="rss"
xmlUrl="http://djangodose.com/everything/feed/" />
</outline>
<outline text="Miscelaneous">
<outline text="dhellmann's CastSampler Feed" type="rss"
xmlUrl="http://www.castsampler.com/cast/feed/rss/dhellmann/"
htmlUrl="http://www.castsampler.com/users/dhellmann/" />
</outline>
</body>
</opml>
ファイルを解析するには、オープンしたファイルハンドラを parse() へ渡します。
from xml.etree import ElementTree
with open('podcasts.opml', 'rt') as f:
tree = ElementTree.parse(f)
print tree
これはデータを読み込み、XML を解析して、 ElementTree オブジェクトを返します。
$ python ElementTree_parse_opml.py
<xml.etree.ElementTree.ElementTree object at 0x10048efd0>
解析されたツリーを横断する¶
順番に全ての子を参照するには、 ElementTree インスタンスを繰り返し処理するジェネレータを生成する iter() を使用してください。
from xml.etree import ElementTree
with open('podcasts.opml', 'rt') as f:
tree = ElementTree.parse(f)
for node in tree.iter():
print node.tag, node.attrib
このサンプルはツリー全体と1つのタグを一緒に表示します。
$ python ElementTree_dump_opml.py
opml {'version': '1.0'}
head {}
title {}
dateCreated {}
dateModified {}
body {}
outline {'text': 'Science and Tech'}
outline {'xmlUrl': 'http://www.publicradio.org/columns/futuretense/podcast.xml', 'text': 'APM: Future Tense', 'type': 'rss', 'htmlUrl': 'http://www.publicradio.org/columns/futuretense/'}
outline {'xmlUrl': 'http://www.npr.org/rss/podcast.php?id=510030', 'text': 'Engines Of Our Ingenuity Podcast', 'type': 'rss', 'htmlUrl': 'http://www.uh.edu/engines/engines.htm'}
outline {'xmlUrl': 'http://www.nyas.org/Podcasts/Atom.axd', 'text': 'Science & the City', 'type': 'rss', 'htmlUrl': 'http://www.nyas.org/WhatWeDo/SciencetheCity.aspx'}
outline {'text': 'Books and Fiction'}
outline {'xmlUrl': 'http://feeds.feedburner.com/podiobooks', 'text': 'Podiobooker', 'type': 'rss', 'htmlUrl': 'http://www.podiobooks.com/blog'}
outline {'xmlUrl': 'http://web.me.com/normsherman/Site/Podcast/rss.xml', 'text': 'The Drabblecast', 'type': 'rss', 'htmlUrl': 'http://web.me.com/normsherman/Site/Podcast/Podcast.html'}
outline {'xmlUrl': 'http://www.tor.com/rss/category/TorDotStories', 'text': 'tor.com / category / tordotstories', 'type': 'rss', 'htmlUrl': 'http://www.tor.com/'}
outline {'text': 'Computers and Programming'}
outline {'xmlUrl': 'http://leo.am/podcasts/mbw', 'text': 'MacBreak Weekly', 'type': 'rss', 'htmlUrl': 'http://twit.tv/mbw'}
outline {'xmlUrl': 'http://leo.am/podcasts/floss', 'text': 'FLOSS Weekly', 'type': 'rss', 'htmlUrl': 'http://twit.tv'}
outline {'xmlUrl': 'http://www.coreint.org/podcast.xml', 'text': 'Core Intuition', 'type': 'rss', 'htmlUrl': 'http://www.coreint.org/'}
outline {'text': 'Python'}
outline {'xmlUrl': 'http://advocacy.python.org/podcasts/pycon.rss', 'text': 'PyCon Podcast', 'type': 'rss', 'htmlUrl': 'http://advocacy.python.org/podcasts/'}
outline {'xmlUrl': 'http://advocacy.python.org/podcasts/littlebit.rss', 'text': 'A Little Bit of Python', 'type': 'rss', 'htmlUrl': 'http://advocacy.python.org/podcasts/'}
outline {'xmlUrl': 'http://djangodose.com/everything/feed/', 'text': 'Django Dose Everything Feed', 'type': 'rss'}
outline {'text': 'Miscelaneous'}
outline {'xmlUrl': 'http://www.castsampler.com/cast/feed/rss/dhellmann/', 'text': "dhellmann's CastSampler Feed", 'type': 'rss', 'htmlUrl': 'http://www.castsampler.com/users/dhellmann/'}
podcast の名前のグループとフィード URL のみを表示するには、ヘッダセクションにある全てのデータを取り除き、 outline ノードのみを対象にして text と xmlUrl 属性を表示します。
from xml.etree import ElementTree
with open('podcasts.opml', 'rt') as f:
tree = ElementTree.parse(f)
for node in tree.iter('outline'):
name = node.attrib.get('text')
url = node.attrib.get('xmlUrl')
if name and url:
print ' %s :: %s' % (name, url)
else:
print name
iter() へ渡す 'outline' という引数は、 'outline' タグをもつノードのみに処理を絞り込みます。
$ python ElementTree_show_feed_urls.py
Science and Tech
APM: Future Tense :: http://www.publicradio.org/columns/futuretense/podcast.xml
Engines Of Our Ingenuity Podcast :: http://www.npr.org/rss/podcast.php?id=510030
Science & the City :: http://www.nyas.org/Podcasts/Atom.axd
Books and Fiction
Podiobooker :: http://feeds.feedburner.com/podiobooks
The Drabblecast :: http://web.me.com/normsherman/Site/Podcast/rss.xml
tor.com / category / tordotstories :: http://www.tor.com/rss/category/TorDotStories
Computers and Programming
MacBreak Weekly :: http://leo.am/podcasts/mbw
FLOSS Weekly :: http://leo.am/podcasts/floss
Core Intuition :: http://www.coreint.org/podcast.xml
Python
PyCon Podcast :: http://advocacy.python.org/podcasts/pycon.rss
A Little Bit of Python :: http://advocacy.python.org/podcasts/littlebit.rss
Django Dose Everything Feed :: http://djangodose.com/everything/feed/
Miscelaneous
dhellmann's CastSampler Feed :: http://www.castsampler.com/cast/feed/rss/dhellmann/
ドキュメントのノードを見つける¶
関連するノードをこのように探してツリー全体を横断するとエラーが発生し易くなります。前節のサンプルは、それぞれの outline ノードでグループ(text 属性のみをもつノード)かどうかを決めるために調べなければなりませんでした。podcast のダウンローダアプリケーション向けに名前やグループをもたない podcast フィード URL のシンプルなリストを作成するには、そのロジックはもっと分かり易い検索特性でノードを探すために findall() を使用すると簡単になります。
前節の変換サンプルの1番目の引数として、全ての outline ノードを探す XPath の引数を渡します。
from xml.etree import ElementTree
with open('podcasts.opml', 'rt') as f:
tree = ElementTree.parse(f)
for node in tree.findall('.//outline'):
url = node.attrib.get('xmlUrl')
if url:
print url
このサンプルのロジックは、本質的には getiterator() を使用するサンプルと同じです。URL が見つからなかったときにグループ名を表示しないことを除けば、それでも URL の存在を確認する必要があります。
$ python ElementTree_find_feeds_by_tag.py
http://www.publicradio.org/columns/futuretense/podcast.xml
http://www.npr.org/rss/podcast.php?id=510030
http://www.nyas.org/Podcasts/Atom.axd
http://feeds.feedburner.com/podiobooks
http://web.me.com/normsherman/Site/Podcast/rss.xml
http://www.tor.com/rss/category/TorDotStories
http://leo.am/podcasts/mbw
http://leo.am/podcasts/floss
http://www.coreint.org/podcast.xml
http://advocacy.python.org/podcasts/pycon.rss
http://advocacy.python.org/podcasts/littlebit.rss
http://djangodose.com/everything/feed/
http://www.castsampler.com/cast/feed/rss/dhellmann/
別のサンプルとして、 outline ノードが深さ2でネストされている構造を利用できます。検索パスを .//outline/outline に変更すると、そのループ処理が outline ノードの深さ2のレベルのみを処理します。
from xml.etree import ElementTree
with open('podcasts.opml', 'rt') as f:
tree = ElementTree.parse(f)
for node in tree.findall('.//outline/outline'):
url = node.attrib.get('xmlUrl')
print url
入力である深さ2でネストされたこれらの全ての outline ノードは、podcast フィードを参照する xmlURL 属性をもっていると予想されるので、このサンプルのループ処理は xmlURL 属性の確認処理を省けます。
$ python ElementTree_find_feeds_by_structure.py
http://www.publicradio.org/columns/futuretense/podcast.xml
http://www.npr.org/rss/podcast.php?id=510030
http://www.nyas.org/Podcasts/Atom.axd
http://feeds.feedburner.com/podiobooks
http://web.me.com/normsherman/Site/Podcast/rss.xml
http://www.tor.com/rss/category/TorDotStories
http://leo.am/podcasts/mbw
http://leo.am/podcasts/floss
http://www.coreint.org/podcast.xml
http://advocacy.python.org/podcasts/pycon.rss
http://advocacy.python.org/podcasts/littlebit.rss
http://djangodose.com/everything/feed/
http://www.castsampler.com/cast/feed/rss/dhellmann/
このサンプルは存在するデータ構造を絞り込んでいますが、もしこの outline ノードがさらに深いツリーで再配置される場合は処理が停止します。
解析されたノード属性¶
findall() と iter() が返す要素は Element オブジェクトです。XML 構文解析ツリーのノードで表されます。それぞれの Element は、XML から引き出したデータへアクセスする属性をもちます。これはやや不自然なサンプル入力ファイル data.xml で説明できます。
1 2 3 4 5 6 7 | <?xml version="1.0" encoding="UTF-8"?>
<top>
<child>This child contains text.</child>
<child_with_tail>This child has regular text.</child_with_tail>And "tail" text.
<with_attributes name="value" foo="bar" />
<entity_expansion attribute="This & That">That & This</entity_expansion>
</top>
|
ノードの “属性” はディクショナリのように動作する attrib プロパティを利用できます。
from xml.etree import ElementTree
with open('data.xml', 'rt') as f:
tree = ElementTree.parse(f)
node = tree.find('./with_attributes')
print node.tag
for name, value in sorted(node.attrib.items()):
print ' %-4s = "%s"' % (name, value)
入力ファイル data.xml の5行目のノードは2つの属性 name と foo をもちます。
$ python ElementTree_node_attributes.py
with_attributes
foo = "bar"
name = "value"
ノードのテキストコンテンツは、終了タグの後ろに続く “tail” のテキストと一緒に利用できます。
from xml.etree import ElementTree
with open('data.xml', 'rt') as f:
tree = ElementTree.parse(f)
for path in [ './child', './child_with_tail' ]:
node = tree.find(path)
print node.tag
print ' child node text:', node.text
print ' and tail text :', node.tail
3行目の child ノードテキストが埋め込まれています。そして、4行目のノードは(全てのスペースを含む) “tail” のテキストがあります。
$ python ElementTree_node_text.py
child
child node text: This child contains text.
and tail text :
child_with_tail
child node text: This child has regular text.
and tail text : And "tail" text.
ドキュメントに埋め込まれた XML エンティティ参照は、便利なことに値が返される前に適切な文字に変換されます。
from xml.etree import ElementTree
with open('data.xml', 'rt') as f:
tree = ElementTree.parse(f)
node = tree.find('entity_expansion')
print node.tag
print ' in attribute:', node.attrib['attribute']
print ' in text :', node.text
自動変換は XML ドキュメントの特定文字を表す実装の詳細が無視されることを意味します。
$ python ElementTree_entity_references.py
entity_expansion
in attribute: This & That
in text : That & This
解析中にイベントを監視する¶
その他の API は、XML ドキュメントをイベントベースで処理するときに便利です。パーサは、タグをオープンするために start イベントを、タグをクローズするために end イベントを生成します。データは、イベントストリームを繰り返し処理する解析フェーズでそのドキュメントから展開されます。これはその後でドキュメント全体を扱う必要がない場合に便利です。そして、解析されたドキュメント全体をメモリに保持する必要がありません。
iterparse() は、イベントの名前とイベントをトリガーにするノードを含むタプルを生成するイテレータを返します。イベントは次のいずれかを指定できます。
- start
- 新しいタグが検出されます。タグの閉じ括弧は処理済みですが、コンテンツではありません。
- end
- 終了タグの閉じ括弧が処理されます。全ての子は既に処理済みです。
- start-ns
- 名前空間の定義を開始します。
- end-ns
- 名前空間の定義を終了します。
from xml.etree.ElementTree import iterparse
depth = 0
prefix_width = 8
prefix_dots = '.' * prefix_width
line_template = '{prefix:<0.{prefix_len}}{event:<8}{suffix:<{suffix_len}} {node.tag:<12} {node_id}'
for (event, node) in iterparse('podcasts.opml', ['start', 'end', 'start-ns', 'end-ns']):
if event == 'end':
depth -= 1
prefix_len = depth * 2
print line_template.format(prefix=prefix_dots,
prefix_len=prefix_len,
suffix='',
suffix_len=(prefix_width - prefix_len),
node=node,
node_id=id(node),
event=event,
)
if event == 'start':
depth += 1
デフォルトでは end イベントのみが生成されます。他のイベントを参照するには、このサンプルのように必要なイベント名のリストを iterparse() へ渡してください。
$ python ElementTree_show_all_events.py
start opml 4299790224
..start head 4299790288
....start title 4299790352
....end title 4299790352
....start dateCreated 4299790544
....end dateCreated 4299790544
....start dateModified 4299790736
....end dateModified 4299790736
..end head 4299790288
..start body 4299791120
....start outline 4299791184
......start outline 4299791248
......end outline 4299791248
......start outline 4299791312
......end outline 4299791312
......start outline 4299791376
......end outline 4299791376
....end outline 4299791184
....start outline 4299791440
......start outline 4299791568
......end outline 4299791568
......start outline 4299791504
......end outline 4299791504
......start outline 4299791632
......end outline 4299791632
....end outline 4299791440
....start outline 4299791696
......start outline 4299791824
......end outline 4299791824
......start outline 4299792016
......end outline 4299792016
......start outline 4299791952
......end outline 4299791952
....end outline 4299791696
....start outline 4299792144
......start outline 4299792208
......end outline 4299792208
......start outline 4299792272
......end outline 4299792272
......start outline 4299800656
......end outline 4299800656
....end outline 4299792144
....start outline 4299800784
......start outline 4299800912
......end outline 4299800912
....end outline 4299800784
..end body 4299791120
end opml 4299790224
イベントスタイルの処理は、XML の入力から他のフォーマットに変換するといったより自然な操作です。このテクニックは、前節のサンプルで podcast のリストを XML ファイルから CSV ファイルに変換するために使用できます。変換された CSV ファイルはスプレッドシートやデータベースアプリケーションで読み込めます。
import csv
from xml.etree.ElementTree import iterparse
import sys
writer = csv.writer(sys.stdout, quoting=csv.QUOTE_NONNUMERIC)
group_name = ''
for (event, node) in iterparse('podcasts.opml', events=['start']):
if node.tag != 'outline':
# outline 以外を無視する
continue
if not node.attrib.get('xmlUrl'):
# カレントグループを覚える
group_name = node.attrib['text']
else:
# podcast エントリを出力する
writer.writerow( (group_name, node.attrib['text'],
node.attrib['xmlUrl'],
node.attrib.get('htmlUrl', ''),
)
)
この変換プログラムは、解析された入力ファイル全体をメモリに保持する必要がありません。入力ファイルからそれぞれのノードで検出されたときに処理するので効率が良くなります。
$ python ElementTree_write_podcast_csv.py
"Science and Tech","APM: Future Tense","http://www.publicradio.org/columns/futuretense/podcast.xml","http://www.publicradio.org/columns/futuretense/"
"Science and Tech","Engines Of Our Ingenuity Podcast","http://www.npr.org/rss/podcast.php?id=510030","http://www.uh.edu/engines/engines.htm"
"Science and Tech","Science & the City","http://www.nyas.org/Podcasts/Atom.axd","http://www.nyas.org/WhatWeDo/SciencetheCity.aspx"
"Books and Fiction","Podiobooker","http://feeds.feedburner.com/podiobooks","http://www.podiobooks.com/blog"
"Books and Fiction","The Drabblecast","http://web.me.com/normsherman/Site/Podcast/rss.xml","http://web.me.com/normsherman/Site/Podcast/Podcast.html"
"Books and Fiction","tor.com / category / tordotstories","http://www.tor.com/rss/category/TorDotStories","http://www.tor.com/"
"Computers and Programming","MacBreak Weekly","http://leo.am/podcasts/mbw","http://twit.tv/mbw"
"Computers and Programming","FLOSS Weekly","http://leo.am/podcasts/floss","http://twit.tv"
"Computers and Programming","Core Intuition","http://www.coreint.org/podcast.xml","http://www.coreint.org/"
"Python","PyCon Podcast","http://advocacy.python.org/podcasts/pycon.rss","http://advocacy.python.org/podcasts/"
"Python","A Little Bit of Python","http://advocacy.python.org/podcasts/littlebit.rss","http://advocacy.python.org/podcasts/"
"Python","Django Dose Everything Feed","http://djangodose.com/everything/feed/",""
"Miscelaneous","dhellmann's CastSampler Feed","http://www.castsampler.com/cast/feed/rss/dhellmann/","http://www.castsampler.com/users/dhellmann/"
カスタムツリービルダーを作成する¶
構文解析のイベントを処理する潜在的にもっと効率の良い方法は、標準のツリービルダーをカスタムして置き換えることです。 ElementTree パーサーは XML を処理するのに XMLTreeBuilder を使用して、その結果を保存するために対象クラスのメソッドを呼び出します。通常の出力は、デフォルトの TreeBuilder クラスが作成する ElementTree インスタンスです。 TreeBuilder を別のクラスに置き換えることで、オーバーヘッドを省いて、 Element ノードがインスタンス化される前にイベントを受け取れます。
前のセクションの XML-to-CSV コンバータはツリービルダーに変換できます。
import csv
from xml.etree.ElementTree import XMLTreeBuilder
import sys
class PodcastListToCSV(object):
def __init__(self, outputFile):
self.writer = csv.writer(outputFile, quoting=csv.QUOTE_NONNUMERIC)
self.group_name = ''
return
def start(self, tag, attrib):
if tag != 'outline':
# outline 以外を無視する
return
if not attrib.get('xmlUrl'):
# カレントグループを覚える
self.group_name = attrib['text']
else:
# podcast エントリを出力する
self.writer.writerow( (self.group_name, attrib['text'],
attrib['xmlUrl'],
attrib.get('htmlUrl', ''),
)
)
def end(self, tag):
# 閉じタグを無視する
pass
def data(self, data):
# ノード内部のデータを無視する
pass
def close(self):
# 特別な処理は何もしない
return
target = PodcastListToCSV(sys.stdout)
parser = XMLTreeBuilder(target=target)
with open('podcasts.opml', 'rt') as f:
for line in f:
parser.feed(line)
parser.close()
PodcastListToCSV は TreeBuilder プロトコルを実装します。新たな XML タグが検出されると、タグ名と属性をもつ start() が呼び出されます。終了タグが現れるときにその名前で end() が呼ばれます。その間、ノードがコンテンツをもつときに data() が呼ばれます(ツリービルダーが “カレント” ノードを保持すると予想される)。全ての入力が処理されると close() が呼ばれます。この処理は XMLTreeBuilder のユーザへ返される値を返します。
$ python ElementTree_podcast_csv_treebuilder.py
"Science and Tech","APM: Future Tense","http://www.publicradio.org/columns/futuretense/podcast.xml","http://www.publicradio.org/columns/futuretense/"
"Science and Tech","Engines Of Our Ingenuity Podcast","http://www.npr.org/rss/podcast.php?id=510030","http://www.uh.edu/engines/engines.htm"
"Science and Tech","Science & the City","http://www.nyas.org/Podcasts/Atom.axd","http://www.nyas.org/WhatWeDo/SciencetheCity.aspx"
"Books and Fiction","Podiobooker","http://feeds.feedburner.com/podiobooks","http://www.podiobooks.com/blog"
"Books and Fiction","The Drabblecast","http://web.me.com/normsherman/Site/Podcast/rss.xml","http://web.me.com/normsherman/Site/Podcast/Podcast.html"
"Books and Fiction","tor.com / category / tordotstories","http://www.tor.com/rss/category/TorDotStories","http://www.tor.com/"
"Computers and Programming","MacBreak Weekly","http://leo.am/podcasts/mbw","http://twit.tv/mbw"
"Computers and Programming","FLOSS Weekly","http://leo.am/podcasts/floss","http://twit.tv"
"Computers and Programming","Core Intuition","http://www.coreint.org/podcast.xml","http://www.coreint.org/"
"Python","PyCon Podcast","http://advocacy.python.org/podcasts/pycon.rss","http://advocacy.python.org/podcasts/"
"Python","A Little Bit of Python","http://advocacy.python.org/podcasts/littlebit.rss","http://advocacy.python.org/podcasts/"
"Python","Django Dose Everything Feed","http://djangodose.com/everything/feed/",""
"Miscelaneous","dhellmann's CastSampler Feed","http://www.castsampler.com/cast/feed/rss/dhellmann/","http://www.castsampler.com/users/dhellmann/"
文字列を解析する¶
小さな XML テキスト、特にプログラムのソースに埋め込まれる可能性がある文字列リテラルを扱うには、 XML() と1つの引数として解析される XML に含まれる文字列を使用してください。
from xml.etree.ElementTree import XML
parsed = XML('''
<root>
<group>
<child id="a">This is child "a".</child>
<child id="b">This is child "b".</child>
</group>
<group>
<child id="c">This is child "c".</child>
</group>
</root>
''')
print 'parsed =', parsed
for elem in parsed:
print elem.tag
if elem.text is not None and elem.text.strip():
print ' text: "%s"' % elem.text
if elem.tail is not None and elem.tail.strip():
print ' tail: "%s"' % elem.tail
for name, value in sorted(elem.attrib.items()):
print ' %-4s = "%s"' % (name, value)
print
parse() とは違って、返り値は ElementTree ではなく Element インスタンスになることに注意してください。 Element は直接イテレータプロトコルをサポートするので getiterator() を呼び出す必要はありません。
$ python ElementTree_XML.py
parsed = <Element 'root' at 0x100499710>
group
group
目的のユニークなノードを識別する id 属性をもつ構造化された XML 向けに、解析結果に対してアクセスするには XMLID() が便利な方法です。
from xml.etree.ElementTree import XMLID
tree, id_map = XMLID('''
<root>
<group>
<child id="a">This is child "a".</child>
<child id="b">This is child "b".</child>
</group>
<group>
<child id="c">This is child "c".</child>
</group>
</root>
''')
for key, value in sorted(id_map.items()):
print '%s = %s' % (key, value)
XMLID() は、 Element オブジェクトとして解析されたツリーを返します。それと一緒に id 属性の文字列をツリーの個別ノードにマッピングするディクショナリも返します。
$ python ElementTree_XMLID.py
a = <Element 'child' at 0x100499850>
b = <Element 'child' at 0x100499910>
c = <Element 'child' at 0x100499b50>
See also
- Outline Processor Markup Language, OPML
- Dave Winer の OPML 仕様とドキュメント
- XML Path Language, XPath
- XML ドキュメントの一部を識別するための構文
- XPath Support in ElementTree
- Fredrick Lundh の ElementTree のオリジナルドキュメントの一部
- csv
- カンマ区切りのファイルを読み書きする