Python で XML をパースする (ElementTree)

ElementTree XML API

Python 2.5 以降には、XML を扱うための標準 API として、ElementTree XML API が用意されています。

ElementTree では、パースした XML を DOM オブジェクトとしてメモリ上に保持するため、XML データを読み込んだあとは、各 XML 要素へ柔軟にアクセスすることができます。

XML ファイルをパースする

ElementTree モジュールが提供している ElementTree.parse 関数を使って、XML ファイルを読み込むことができます。 ElementTree.parse 関数は、読み込んだ XML をパースして ElementTree オブジェクトとして返します。 ElementTree オブジェクトは、XML ツリー全体を表現するオブジェクトです。 XML ツリーの先頭要素を表す Element オブジェクトは、ElementTree#getroot() メソッドで取得することができます。

input.xml(テスト用の XML ファイル)
<tree name="hello">
  <trunk>...</trunk>
</tree>
main.py
from xml.etree import ElementTree

# XML ファイルから ElementTree オブジェクトを生成
tree = ElementTree.parse('input.xml')

# 先頭要素を表す Element オブジェクトを取得
elem = tree.getroot()
print(type(elem))   # => <class 'xml.etree.ElementTree.Element'>
print(elem)         # => <Element 'tree' at 0x105499c60>
print(elem.tag)     # => tree
print(elem.attrib)  # => {'name': 'hello'}

XML 形式の文字列をパースする

XML ファイルではなく、XML 形式のテキストをパースしたいときは、ElementTree.fromstring(str) 関数を使用します。 戻り値は、先頭要素を表す Element オブジェクトになります。

main.py
from xml.etree import ElementTree

# XML 文字列をパースして Element オブジェクトを生成
elem = ElementTree.fromstring('<tree name="hello"><trunk>...</trunk></tree>')
print(elem.tag)     #=> tree
print(elem.attrib)  #=> {'name': 'hello'}

Element オブジェクトから要素の情報を取得する

Element オブジェクトは 1 つの XML 要素を表現しており、下記のようなプロパティやメソッドが用意されています。 要素に含まれるテキストノードや属性を表すためのオブジェクトは存在せず、Element オブジェクトに付随する情報として管理されていることに注意してください。

属性説明
Element#tagタグ名を取得
Element#textその要素の先頭にあるテキストノードを取得(<b>これ</b>
Element#tailその要素の直後にあるテキストノードを取得(<b>...</b>これ
Element#attribdictionary 形式で属性をすべて取得
Element#get(key, default=None)指定したキーの属性を取得
Element#items()(name, value) のペアで属性をすべて取得
Element#keys()属性のキーをすべて取得

下記の例では、各要素のタグ名や、属性、テキストノードを再帰的に出力しています。 子要素を取得するには、Element 要素自身を for-in ループでイテレートします。

books.xml
<?xml version="1.0"?>
<books>
  <book id="001">
    <title>Title 1</title>
    <author>Author 1</author>
  </book>
  <book id="002">
    <title>Title 2</title>
    <author>Author 2</author>
  </book>
</books>
parse_books.py
from xml.etree import ElementTree

def dump_node(node, indent=0):
    print("{}{} {} {}".format('    ' * indent, node.tag, node.attrib, node.text.strip()))
    for child in node:
        dump_node(child, indent + 1)

if __name__ == '__main__':
    tree = ElementTree.parse('books.xml')
    dump_node(tree.getroot())
実行結果
$ python parse_books.py
books {}
    book {'id': '001'}
        title {} Title 1
        author {} Author 1
    book {'id': '002'}
        title {} Title 2
        author {} Author 2