PythonでElementTreeを使ってXMLを処理する方法

ElementTreeはpythonXMLを扱うためのライブラリです。バージョン2.5からはpythonに標準で内蔵されています。
このライブラリを使うと、XMLをパースしてプログラム内で利用しやすい形に変換したり、XMLファイルを生成したりすることが出来ます。そこで今回は、XMLをパースして利用する方法についてまとめたいと思います。

準備

Python2.5以降にはElementTreeが標準で内蔵されているため、パッケージを個別で入手する必要はありません。
以下のようにインポートするだけで利用できます。

from xml.etree.ElementTree import *

Python2.5より古いバージョンを利用している場合は、

からパッケージを入手し、以下のようにインポートして下さい。

from elementtree.ElementTree import *

利用データ

今回の説明では、以下の内容のXMLファイルをサンプルとして扱います。

<window width="1920">
	<title font="large" color="red">sample</title>
	<buttonbox>
		<button>OK</button>
		<button>Cancel</button>
	</buttonbox>
</window>

Elementの作成

ElementTreeを使う上でメインとなるのがElementというオブジェクトです。まずは、このElementの作成方法について以下に例を示します。

# 文字列から作成
xmlString = '<window width="1920"><title font="large" color="red">sample</title><buttonbox><button>OK</button><button>Cancel</button></buttonbox></window>'
elem = fromstring(xmlString) # ルート要素を取得(Element型)

#ファイルから作成
tree = parse("sample.xml") # 返値はElementTree型
elem = tree.getroot() # ルート要素を取得(Element型)

XMLを表す文字列からElementを作成するには、fromstringメソッドを呼び出します。WebAPIなどから取得したデータをパースしたい場合はこの方法を利用することが多いと思います。
また、XMLファイルからデータを読み込む場合はparseというメソッドを利用します。parseの返値はElementTree型となります。このElementTree型はXMLファイルからデータを読み込んだり、書き込んだりする際に利用されるラッパークラスです。ここでは、とりあえず上記の様にparseメソッドを呼んで、その後にgetrootメソッドを呼べばElement型のルート要素が取得できると覚えておけば問題ありません。

データの参照

タグ名、属性(attribute)を参照する方法。

# 要素のタグを取得
print elem.tag
# attributeの取得
print elem.get("width")
# デフォルトを指定してattributeを取得
print elem.get("height", "1200")
# attribute名のリスト取得
print elem.keys()
# (attribute, value)形式タプルのリスト取得
print elem.items()

実行結果
window
1920
1200
['width']
[('width', '1920')]

要素の検索

条件にマッチする要素を検索する方法。

# 条件に一番最初にマッチした要素を返す
print elem.find(".//buttonbox").tag
# 条件にマッチする要素をリストで返す
for e in elem.findall(".//button"):
    print e.tag
# 条件にマッチする一番最初の要素のテキストを返す
print elem.findtext(".//button")
# findtextを分けて書くと以下の通り
print elem.find(".//button").text

実行結果
buttonbox


button
button


OK
OK

find,findall,findtextの引数にはXPath形式を利用することが出来ます。詳細については以下を参照して下さい。
http://effbot.org/zone/element-xpath.htm

要素への順次アクセス

XML内の要素を1つずつ参照する方法。

# すべての要素にアクセス
for e in elem.getiterator():
    print e.tag
# 条件指定(tag名を指定)
for e in elem.getiterator("button"):
    print e.tag
# 子要素のリストを取得(再帰的ではなく、直系の子要素のみ)
for e in list(elem):
    print e.tag

実行結果
window
title
buttonbox
button
button


button
button


title
buttonbox

子要素から親要素へのアクセス

子要素と親要素の関係を保持する方法。公式のマニュアルではジェネレーターを定義する方法と、対応関係を保持するマップを作成してしまう方法が紹介されています。

# ジェネレーターを使った方法
def iterparent(elem):
    for parent in elem.getiterator():
        for child in parent:
            yield parent, child

for p,c in iterparent(elem):
    print c.tag+":"+p.tag

# (child, parent)形式のマップを生成する方法
parent_map = dict((c, p) for p in tree.getiterator() for c in p)
for k in parent_map.keys():
    print k.tag+":"+parent_map.get(k).tag

実行結果
title:window
buttonbox:window
button:buttonbox
button:buttonbox


title:window
buttonbox:window
button:buttonbox
button:buttonbox

以上です。