API連携やデータ交換でXMLファイルを扱う機会は意外と多いですよね。
「XMLって複雑そう…」と思っている方も多いかもしれませんが、Pythonを使えばとても簡単にXMLの読み込みや書き込みができるんです。
今回は、Python標準ライブラリのElementTreeを使って、XMLを自在に操る方法を解説していきます。初心者の方でもすぐに実践できるように、実例をたっぷり用意しましたよ!
ElementTreeとは?なぜこれを使うの?

ElementTreeは、Pythonに最初から入っている標準ライブラリです。
追加でインストールする必要がなく、すぐに使えるのが大きなメリットですね。軽量で高速、そして使いやすいという三拍子揃ったライブラリなんです。
主な特徴
- 標準ライブラリ:追加インストール不要
- シンプルなAPI:直感的で分かりやすい
- 高速処理:大きなファイルでも効率的
- 豊富な機能:読み込み、書き込み、検索、編集すべてに対応
基本的なインポート方法
ElementTreeを使うには、以下のようにインポートします。
import xml.etree.ElementTree as ET
慣習としてETという短い名前をつけることが多いですよ。毎回長い名前を書くのは大変ですからね!
XMLファイルを読み込んでみよう
まずは、XMLファイルを読み込んで内容を表示する方法から始めましょう。
サンプルXMLファイル
こんなXMLファイルがあるとします。
<?xml version="1.0" encoding="UTF-8"?>
<books>
<book id="1">
<title>Python入門</title>
<author>山田太郎</author>
<price>2500</price>
</book>
<book id="2">
<title>データ分析の基礎</title>
<author>佐藤花子</author>
<price>3200</price>
</book>
</books>
このファイルをbooks.xmlとして保存しておきましょう。
読み込みコード
import xml.etree.ElementTree as ET
# XMLファイルを読み込む
tree = ET.parse('books.xml')
root = tree.getroot()
# ルート要素を表示
print(f"ルート要素: {root.tag}")
# すべてのbook要素を取得
for book in root.findall('book'):
book_id = book.get('id')
title = book.find('title').text
author = book.find('author').text
price = book.find('price').text
print(f"ID: {book_id}")
print(f"タイトル: {title}")
print(f"著者: {author}")
print(f"価格: {price}円")
print("---")
実行結果:
ルート要素: books
ID: 1
タイトル: Python入門
著者: 山田太郎
価格: 2500円
---
ID: 2
タイトル: データ分析の基礎
著者: 佐藤花子
価格: 3200円
---
コードの流れはシンプルですよね。parse()でファイルを読み込み、getroot()でルート要素を取得するだけです。
文字列からXMLを読み込む方法
ファイルではなく、文字列として持っているXMLを解析したい場合もあります。
import xml.etree.ElementTree as ET
xml_string = """
<person>
<name>田中一郎</name>
<age>30</age>
<city>東京</city>
</person>
"""
# 文字列からXMLを解析
root = ET.fromstring(xml_string)
name = root.find('name').text
age = root.find('age').text
city = root.find('city').text
print(f"名前: {name}")
print(f"年齢: {age}歳")
print(f"都市: {city}")
実行結果:
名前: 田中一郎
年齢: 30歳
都市: 東京
APIから取得したXMLデータを処理するときは、このfromstring()メソッドが便利ですよ。
XMLの要素を検索する方法
ElementTreeには、要素を検索するための便利なメソッドがいくつかあります。
主な検索メソッド
| メソッド | 説明 | 戻り値 |
|---|---|---|
find() | 最初にマッチした要素を返す | 1つの要素 |
findall() | マッチしたすべての要素を返す | 要素のリスト |
findtext() | 最初にマッチした要素のテキストを返す | 文字列 |
実例で理解しよう
import xml.etree.ElementTree as ET
xml_data = """
<library>
<section name="技術書">
<book>Python実践入門</book>
<book>Web開発の教科書</book>
</section>
<section name="小説">
<book>夏の物語</book>
<book>冬の記憶</book>
</section>
</library>
"""
root = ET.fromstring(xml_data)
# 最初のsection要素を取得
first_section = root.find('section')
print(f"最初のセクション: {first_section.get('name')}")
# すべてのsection要素を取得
all_sections = root.findall('section')
print(f"セクション数: {len(all_sections)}")
# 技術書セクションの最初の本を取得
tech_section = root.find("section[@name='技術書']")
if tech_section is not None:
first_book = tech_section.findtext('book')
print(f"技術書の最初の本: {first_book}")
XPath風の記法も使えるので、条件に合った要素を簡単に絞り込めます。
属性(Attribute)の取得と設定

XML要素には属性がついていることがよくあります。
属性を取得する
import xml.etree.ElementTree as ET
xml_data = """
<product id="A001" category="electronics" stock="50">
<name>ワイヤレスマウス</name>
</product>
"""
root = ET.fromstring(xml_data)
# 単一の属性を取得
product_id = root.get('id')
print(f"商品ID: {product_id}")
# すべての属性を辞書で取得
all_attrs = root.attrib
print(f"すべての属性: {all_attrs}")
# 特定の属性が存在するかチェック
if 'stock' in root.attrib:
stock = root.get('stock')
print(f"在庫数: {stock}個")
実行結果:
商品ID: A001
すべての属性: {'id': 'A001', 'category': 'electronics', 'stock': '50'}
在庫数: 50個
get()メソッドは、属性が存在しない場合にNoneを返すので、安全に使えます。
属性を設定・変更する
import xml.etree.ElementTree as ET
xml_data = "<product id='A001'><name>キーボード</name></product>"
root = ET.fromstring(xml_data)
# 新しい属性を追加
root.set('price', '5000')
root.set('currency', 'JPY')
# 既存の属性を変更
root.set('id', 'A002')
print(ET.tostring(root, encoding='unicode'))
set()メソッドで簡単に属性を追加・変更できますよ。
新しいXMLを作成する方法
ElementTreeを使えば、ゼロからXMLを作ることもできます。
import xml.etree.ElementTree as ET
# ルート要素を作成
root = ET.Element('employees')
# 従業員1を追加
emp1 = ET.SubElement(root, 'employee', id='E001')
ET.SubElement(emp1, 'name').text = '鈴木太郎'
ET.SubElement(emp1, 'department').text = '営業部'
ET.SubElement(emp1, 'salary').text = '400000'
# 従業員2を追加
emp2 = ET.SubElement(root, 'employee', id='E002')
ET.SubElement(emp2, 'name').text = '高橋花子'
ET.SubElement(emp2, 'department').text = '開発部'
ET.SubElement(emp2, 'salary').text = '450000'
# ツリーを作成
tree = ET.ElementTree(root)
# ファイルに保存(整形あり)
ET.indent(tree, space=' ') # Python 3.9以降
tree.write('employees.xml', encoding='utf-8', xml_declaration=True)
print("XMLファイルを作成しました!")
生成されるXMLファイル:
<?xml version='1.0' encoding='utf-8'?>
<employees>
<employee id="E001">
<name>鈴木太郎</name>
<department>営業部</department>
<salary>400000</salary>
</employee>
<employee id="E002">
<name>高橋花子</name>
<department>開発部</department>
<salary>450000</salary>
</employee>
</employees>
SubElement()を使うと、親要素に子要素を次々と追加できて便利です。
XMLの要素を編集・削除する
既存のXMLを編集したり、不要な要素を削除したりすることもできます。
要素の編集
import xml.etree.ElementTree as ET
tree = ET.parse('books.xml')
root = tree.getroot()
# 最初の本の価格を変更
first_book = root.find('book')
price_elem = first_book.find('price')
price_elem.text = '2800' # 価格を更新
# ファイルに保存
tree.write('books_updated.xml', encoding='utf-8', xml_declaration=True)
テキストや属性を変更したら、必ずwrite()でファイルに保存しましょう。
要素の削除
import xml.etree.ElementTree as ET
tree = ET.parse('books.xml')
root = tree.getroot()
# ID=2の本を削除
for book in root.findall('book'):
if book.get('id') == '2':
root.remove(book)
break
# 保存
tree.write('books_modified.xml', encoding='utf-8', xml_declaration=True)
remove()メソッドで指定した子要素を削除できます。
XPathで高度な検索をする
XPathを使うと、より複雑な条件で要素を検索できます。
import xml.etree.ElementTree as ET
xml_data = """
<store>
<product category="food" price="500">りんご</product>
<product category="food" price="300">バナナ</product>
<product category="electronics" price="5000">マウス</product>
<product category="electronics" price="8000">キーボード</product>
</store>
"""
root = ET.fromstring(xml_data)
# 食品カテゴリの商品をすべて取得
foods = root.findall("./product[@category='food']")
print("食品:")
for food in foods:
print(f" - {food.text} ({food.get('price')}円)")
# 価格が1000円以上の商品を取得(ElementTreeでは制限あり)
# より高度な検索にはlxmlライブラリを使用することをおすすめします
実行結果:
食品:
- りんご (500円)
- バナナ (300円)
ElementTreeのXPathサポートは基本的な機能に限られます。もっと複雑な検索が必要な場合は、lxmlライブラリの使用を検討しましょう。
エラーハンドリング:安全にXMLを扱う
XMLの読み込みや解析では、エラーが発生する可能性があります。
import xml.etree.ElementTree as ET
def safe_parse_xml(filename):
try:
tree = ET.parse(filename)
root = tree.getroot()
return root
except FileNotFoundError:
print(f"エラー: {filename} が見つかりません")
return None
except ET.ParseError as e:
print(f"XML解析エラー: {e}")
return None
# 使用例
root = safe_parse_xml('data.xml')
if root is not None:
# 処理を続ける
print("XMLの読み込みに成功しました")
else:
print("XMLの読み込みに失敗しました")
try-exceptを使って、適切にエラーを処理することが大切です。
実践例:天気予報データの解析
実際のユースケースとして、天気予報のXMLデータを解析してみましょう。
import xml.etree.ElementTree as ET
weather_xml = """
<weather_forecast>
<city name="東京">
<date>2024-03-20</date>
<temperature>
<high>18</high>
<low>10</low>
</temperature>
<condition>晴れ</condition>
<humidity>60</humidity>
</city>
<city name="大阪">
<date>2024-03-20</date>
<temperature>
<high>20</high>
<low>12</low>
</temperature>
<condition>曇り</condition>
<humidity>65</humidity>
</city>
</weather_forecast>
"""
root = ET.fromstring(weather_xml)
print("本日の天気予報")
print("=" * 40)
for city in root.findall('city'):
city_name = city.get('name')
date = city.findtext('date')
high = city.findtext('temperature/high')
low = city.findtext('temperature/low')
condition = city.findtext('condition')
humidity = city.findtext('humidity')
print(f"\n【{city_name}】")
print(f"日付: {date}")
print(f"気温: {low}℃ ~ {high}℃")
print(f"天気: {condition}")
print(f"湿度: {humidity}%")
実行結果:
本日の天気予報
========================================
【東京】
日付: 2024-03-20
気温: 10℃ ~ 18℃
天気: 晴れ
湿度: 60%
【大阪】
日付: 2024-03-20
気温: 12℃ ~ 20℃
天気: 曇り
湿度: 65%
このように、実用的なデータ処理も簡単にできますね。
より高度な機能が必要なら:lxmlライブラリ
ElementTreeは軽量で使いやすいですが、より高度な機能が必要な場合はlxmlライブラリがおすすめです。
lxmlの特徴
- 完全なXPathサポート
- XMLスキーマ検証
- より高速な処理
- 名前空間の高度な処理
インストール方法
pip install lxml
基本的な使い方
from lxml import etree
# ElementTreeと似たAPIで使える
tree = etree.parse('data.xml')
root = tree.getroot()
# XPathの完全サポート
results = root.xpath('//book[@price > 2000]')
大規模なXML処理や、複雑な検索が必要な場合は、lxmlへの移行を検討しましょう。
よくある質問
Q: 大きなXMLファイルを扱うときの注意点は?
A: ElementTreeは、ファイル全体をメモリに読み込みます。非常に大きなファイル(数GB以上)の場合は、iterparse()を使ったストリーミング処理を検討してください。これなら少ないメモリで処理できますよ。
Q: XMLの整形(インデント)はどうすればいい?
A: Python 3.9以降ならET.indent()が使えます。それ以前のバージョンでは、lxmlや外部ライブラリを使うか、自分で整形関数を作る必要があります。
Q: 名前空間(Namespace)が含まれるXMLはどう扱う?
A: ElementTreeは名前空間もサポートしています。ただし、記述が少し複雑になるので、名前空間を多用する場合はlxmlの方が扱いやすいでしょう。
まとめ:PythonでXMLは怖くない!
PythonのElementTreeを使ったXML処理について、重要なポイントをおさらいします。
今日学んだこと:
- ElementTreeは標準ライブラリで追加インストール不要
parse()でファイル、fromstring()で文字列を読み込めるfind()とfindall()で要素を検索できるget()とset()で属性を操作できるSubElement()で新しいXMLを作成できる- XPathで高度な検索が可能
- エラーハンドリングで安全な処理を実現
XMLは一見複雑に見えますが、ElementTreeを使えば驚くほど簡単に扱えます。
API連携、設定ファイルの読み書き、データ交換など、XMLを使う場面は意外と多いですよね。今回学んだテクニックを使って、ぜひ実際のプロジェクトでXML処理に挑戦してみてください。
最初は小さなXMLから始めて、徐々に複雑なデータ構造にチャレンジしていくといいでしょう。実践を重ねるほど、XMLの扱いに慣れていきますよ!


コメント