2022-02-05に投稿

Python 標準ライブラリ xml.etree.ElementTree XMLのパース

Pythonの標準にあるXMLの解析で使えるライブラリxml.etree.ElementTreeの使い方です。

概要

XML文字列を読み込んで、内容を解析(パース)した結果に以下のようにアクセスできる。

import xml.etree.ElementTree as ET

xml_string = '''\
<?xml version="1.0"?>
<rootTag attribute_sample="123">
    <person some_attribute="AAA">
        <name>Taro</name>
        <birthDate>2000-01-01</birthDate>
    </person>
    <person some_attribute="BBB">
        <name>Jiro</name>
        <birthDate>2003-10-12</birthDate>
        <items>
            <item>
                <name>X001</name>
                <size>12.3</size>
            </item>
            <item>
                <name>X002</name>
                <size>23.4</size>
            </item>
        </items>
    </person>
    <person some_attribute="CCC">
        <name>Hanako</name>
        <birthDate>2001-07-10</birthDate>
    </person>
</rootTag>
'''

root = ET.fromstring(xml_string) # Element

root.tag # => 'rootTag'
root.attrib # => {'attribute_sample': '123'}

for child in root:
    print(f"{child.tag} {child.attrib}")
    # person {'some_attribute': 'AAA'}
    # person {'some_attribute': 'BBB'}
    # person {'some_attribute': 'CCC'}

ElementTreeはXML要素全体に対応するオブジェクトで、
ElementはXMLの要素1つに対応するオブジェクトとなっている。

上記はXML文字列からXML要素(Element)を取得する例になっている。

XML要素 Elementの読み込み

xml.etree.ElementTree.parse(XMLファイルのパス)を使うとElementTreeのオブジェクトを取得できる。

tree = ET.parse('sample.xml') # xml.etree.ElementTree.ElementTree object
root = tree.getroot() # Element 

引数にはファイルオブジェクトも指定可能。

with open('./sample.xml', mode='r', encoding='utf-8') as f:
    tree = ET.parse(f) # xml.etree.ElementTree.ElementTree object
    root = tree.getroot() # Element 

XML要素 Element

子要素のイテレータ

Elementは子要素をイテレートする。

for child in root:
    print(f"{child.tag} {child.attrib}")
    # person {'some_attribute': 'AAA'}
    # person {'some_attribute': 'BBB'}
    # person {'some_attribute': 'CCC'}

フィールド

# タグの名称
root.tag # => 'rootTag'
# 属性の辞書
root.attrib # => {'attribute_sample': '123'}
# テキスト要素
root.text # => '\n    '

メソッド

タグの名称やxPathでの要素取得は以下のように行う。

# 子要素(複数の場合最初の1つ)
root.find('person') # Element
root.find('person/items') # Element
root.find('person/items/item') # Element
root.find('items') # None

## 子要素の全て
root.findall('person') # Element
root.findall('name') # []

## テキスト
root.findtext('person/name') # 'Taro'

子孫までを繰り返しての取得は次のように行える。

for name_element in root.iter('name'):
    print(f"{name_element.text}")
    # Taro Jiro X001 X002 Hanako

iterfindはrootに対して条件を指定して要素を取得する。

list(root.iterfind('name')) # => []

for name_element in root.iterfind('person/name'):
    print(f"{name_element.text}")
    # Taro Jiro Hanako

指定した要素以下のすべてのテキストノードはitertextで取得できる。

list(root.find('person').itertext())
['\n        ', 'Taro', '\n        ', '2000-01-01', '\n    ']

属性の設定と取得は以下の様に行う。

root.get('attribute_sample') # => '123'

root.set('attribute_sample','321')

root.items() # => [('attribute_sample', '321')]

root.keys() # => ['attribute_sample']

要素の変更は次のメソッドを使用する。

element = ET.fromstring('<root><A>aaa</A></root>')

# 新規要素作成
b_item = ET.Element('B')
sub_item = ET.SubElement(b_item,'sub')
sub_item.text = 'SS'

# 要素の追加
element.append(b_item)
ET.tostring(element) # => b'<root><A>aaa</A><B><sub>SS</sub></B></root>'

# 要素の削除
element.remove(b_item)
ET.tostring(element) # => b'<root><A>aaa</A></root>'

# 新規要素作成
new_items = list()
for i in range(3):
    sub = ET.Element('item')
    sub.text = str(i+1)
    new_items.append(sub)

# 要素の複数追加
element.extend(new_items)
ET.tostring(element) # => b'<root><A>aaa</A><item>1</item><item>2</item><item>3</item></root>'

# 2つ目のitem要素
item_second = element.find('item[2]')

# 指定位置に要素を挿入
c_item =  ET.Element('C')
element.insert(3, c_item)
ET.tostring(element) # => b'<root><A>aaa</A><item>1</item><item>2</item><C /><item>3</item></root>'

# 要素のクリア
element.clear()
ET.tostring(element) # => b'<root />'

XMLツリー ElementTree

メソッド

# ルート要素の取得
tree.getroot() # => <Element 'rootTag' at 0x000001BD56DB2EA0

# 指定した名称・XPathで取得(最初の1つのみ)
tree.find('person') # => <Element 'person' at …>

# 指定した名称・XPathで取得
tree.findall('person') # => [<Element 'person' at …>, <Element 'person' at …>, <Element 'person' at …>]

# 指定した名称・XPathのテキストノードを取得
tree.findtext('person') # => '\n        '


for element in tree.iter():
    print(f"{element.tag} {element.text}")
    # => 全タグについて出力

for element in tree.iter('name'):
    print(f"{element.text}")
    # Taro Jiro X001 X002 Hanako
    # 指定した全パスについて出力

for element in tree.iterfind'person/name'):
    print(f"{element.text}")
    # Taro Jiro Hanako
    # ルートからみた指定したパスについて出力

list(tree.iterfind('name')) # => []

参考

cpython/ElementTree.py at 3.10 · python/cpython · GitHub
xml.etree.ElementTree --- ElementTree XML API

Originally published at marusankakusikaku.jp
ツイッターでシェア
みんなに共有、忘れないようにメモ

maru3kaku4kaku

Pythonこつこつ学習中。よく忘れる。

Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

有料記事を販売できるようになりました!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?

コメント