「設定ファイルをXML形式で保存したい」
「WebAPIから返ってきたXMLデータを解析したい」
「XMLファイルの中身を読み込んで編集したい」
プログラミングをしていると、XML(エックスエムエル)形式のデータを扱う場面って意外と多いですよね。
そんな時に活躍するのが、Pythonの標準ライブラリに含まれているElementTreeです。追加インストール不要で、XMLの読み込み・作成・編集が簡単にできる便利なツールなんです。
この記事では、ElementTreeの基本から実践的な使い方まで、初心者の方でも分かるように丁寧に解説していきますね。
そもそもXMLって何?基礎知識をおさらい

ElementTreeの説明に入る前に、XMLについて簡単に確認しておきましょう。
XMLとは
XMLは「eXtensible Markup Language(拡張可能なマークアップ言語)」の略で、データを構造的に記述するための形式です。
HTMLと似た見た目をしていますが、HTMLが「Webページの表示」を目的としているのに対し、XMLは「データの保存や受け渡し」を目的としています。
XMLの基本構造
実際のXMLファイルを見てみましょう:
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book category="fiction">
<title>ハリー・ポッター</title>
<author>J.K.ローリング</author>
<year>1997</year>
<price>2000</price>
</book>
<book category="science">
<title>ホーキング、宇宙を語る</title>
<author>スティーヴン・ホーキング</author>
<year>1988</year>
<price>1500</price>
</book>
</bookstore>
構成要素:
- 宣言部:
<?xml version="1.0"?>(ファイルの最初) - 要素(エレメント):
<book>や<title>など - 属性(アトリビュート):
category="fiction"のような付加情報 - テキスト:タグで囲まれた中身の文字列
このように階層構造(ツリー構造)でデータを表現するのがXMLの特徴です。
ElementTreeとは?基本を押さえよう
ElementTreeの正体
ElementTreeは、PythonでXMLを扱うための標準ライブラリです。正式にはxml.etree.ElementTreeという名前で、Python本体に最初から含まれています。
つまり、追加でインストールする必要がなく、すぐに使い始められるんです。これが大きな魅力ですね。
なぜElementTreeが便利なのか
シンプルで分かりやすい
XMLの複雑な仕様を意識せず、Pythonらしいコードでデータを扱えます。
標準ライブラリだから安心
外部ライブラリに依存しないので、環境構築が楽です。
十分な機能
読み込み、検索、作成、編集と、基本的な操作は全てカバーしています。
軽量で高速
大きなXMLファイルもスムーズに処理できます。
他の選択肢もある?
ElementTree以外にも、XMLを扱うライブラリはいくつかあります:
- lxml:より高機能で高速(別途インストール必要)
- minidom:DOMベースの処理(標準ライブラリ)
- xmltodict:XMLを辞書型に変換(別途インストール必要)
でも、まず最初に学ぶならElementTreeが断然おすすめです。シンプルで扱いやすく、ほとんどのケースで十分な性能を発揮してくれますよ。
ElementTreeの基本的な使い方
それでは、実際にコードを書いていきましょう。
インポート方法
まずはライブラリをインポートします。一般的には省略名を使います:
import xml.etree.ElementTree as ET
このas ETという書き方で、長い名前を短く扱えるようになります。多くのコード例でこの形式が使われていますね。
XMLファイルを読み込む
最も基本的な操作、ファイルの読み込みからスタートです。
import xml.etree.ElementTree as ET
# XMLファイルを読み込む
tree = ET.parse('books.xml')
# ルート要素を取得
root = tree.getroot()
print(root.tag) # 'bookstore' と表示される
解説:
ET.parse()でファイル全体を読み込みますgetroot()でルート要素(最上位の要素)を取得しますroot.tagで要素のタグ名を確認できます
文字列からXMLを読み込む
ファイルではなく、文字列として持っているXMLデータを読み込むこともできます:
import xml.etree.ElementTree as ET
xml_string = '''
<bookstore>
<book>
<title>サンプル本</title>
</book>
</bookstore>
'''
# 文字列からXMLを解析
root = ET.fromstring(xml_string)
print(root.tag) # 'bookstore' と表示される
ET.fromstring()を使うと、文字列から直接要素を作れます。WebAPIのレスポンスを処理する時などに便利ですね。
要素の取得と検索
XMLから必要なデータを取り出す方法を見ていきましょう。
子要素を取得する
全ての子要素を取得:
import xml.etree.ElementTree as ET
tree = ET.parse('books.xml')
root = tree.getroot()
# 直接の子要素を全て取得
for child in root:
print(child.tag, child.attrib)
# book {'category': 'fiction'}
# book {'category': 'science'}
forループで子要素を1つずつ処理できます。
特定のタグの子要素だけ取得:
# <book>要素だけを取得
for book in root.findall('book'):
title = book.find('title').text
print(title)
# ハリー・ポッター
# ホーキング、宇宙を語る
findall()で特定のタグを持つ要素を全て取得します。
要素のテキストと属性を取得
for book in root.findall('book'):
# テキスト内容を取得
title = book.find('title').text
author = book.find('author').text
# 属性を取得
category = book.get('category')
print(f'{title} by {author} ({category})')
ポイント:
.textでタグ内のテキストを取得.get('属性名')で属性の値を取得
XPathで検索する
より柔軟な検索には、XPath(エックスパス)という記法が使えます:
# 全ての<title>要素を検索(階層を問わず)
titles = root.findall('.//title')
for title in titles:
print(title.text)
# category属性が"fiction"の<book>要素を検索
fiction_books = root.findall(".//book[@category='fiction']")
for book in fiction_books:
title = book.find('title').text
print(title)
よく使うXPath表現:
.//タグ名:全ての階層から検索./タグ名:直下の子要素だけ検索[@属性名='値']:属性で絞り込み[数字]:n番目の要素を取得(1始まり)
要素が存在するか確認
要素が見つからない時の対処も重要です:
# findは見つからない時Noneを返す
price_element = book.find('price')
if price_element is not None:
price = price_element.text
print(f'価格: {price}円')
else:
print('価格情報なし')
if element is not None:で存在チェックをするのが安全です。
XMLの作成と編集

ElementTreeでは、XMLデータを作ったり変更したりすることもできます。
新しいXMLを作成する
ゼロから新しいXML文書を作ってみましょう:
import xml.etree.ElementTree as ET
# ルート要素を作成
root = ET.Element('bookstore')
# 子要素を作成
book = ET.SubElement(root, 'book', category='programming')
title = ET.SubElement(book, 'title')
title.text = 'Python入門'
author = ET.SubElement(book, 'author')
author.text = '山田太郎'
year = ET.SubElement(book, 'year')
year.text = '2023'
# ツリーオブジェクトを作成
tree = ET.ElementTree(root)
# ファイルに保存
tree.write('new_books.xml', encoding='utf-8', xml_declaration=True)
解説:
ET.Element()でルート要素を作成ET.SubElement()で子要素を追加.textでテキスト内容を設定tree.write()でファイルに保存
既存のXMLを編集する
既にあるXMLファイルの内容を変更することもできます:
import xml.etree.ElementTree as ET
# XMLを読み込む
tree = ET.parse('books.xml')
root = tree.getroot()
# 特定の要素を見つけて編集
for book in root.findall('book'):
title = book.find('title')
if title.text == 'ハリー・ポッター':
# 価格を変更
price = book.find('price')
price.text = '2500' # 2000円から2500円に値上げ
# 変更を保存
tree.write('books_updated.xml', encoding='utf-8', xml_declaration=True)
要素を追加する
新しい本を既存のリストに追加してみます:
# 新しい<book>要素を作成
new_book = ET.SubElement(root, 'book', category='technology')
ET.SubElement(new_book, 'title').text = 'AI入門'
ET.SubElement(new_book, 'author').text = '佐藤花子'
ET.SubElement(new_book, 'year').text = '2024'
ET.SubElement(new_book, 'price').text = '3000'
# 保存
tree.write('books_added.xml', encoding='utf-8', xml_declaration=True)
要素を削除する
不要な要素を削除することもできます:
# 1997年以前の本を削除
for book in root.findall('book'):
year = book.find('year')
if int(year.text) < 1997:
root.remove(book)
# 保存
tree.write('books_filtered.xml', encoding='utf-8', xml_declaration=True)
root.remove(要素)で子要素を削除できます。
実践的な使用例
実際のプロジェクトでよく使われるパターンをご紹介します。
例1:設定ファイルの読み込み
アプリケーションの設定をXMLで管理するケース:
import xml.etree.ElementTree as ET
def load_config(filename):
"""設定ファイルを読み込んで辞書で返す"""
tree = ET.parse(filename)
root = tree.getroot()
config = {}
# データベース設定
db = root.find('database')
config['db_host'] = db.find('host').text
config['db_port'] = int(db.find('port').text)
config['db_name'] = db.find('name').text
# アプリケーション設定
app = root.find('application')
config['app_name'] = app.find('name').text
config['debug_mode'] = app.find('debug').text == 'true'
return config
# 使い方
config = load_config('config.xml')
print(f"データベース: {config['db_host']}:{config['db_port']}")
例2:RSSフィードの解析
ブログのRSSフィード(更新情報)を読み込むケース:
import xml.etree.ElementTree as ET
import urllib.request
def parse_rss(url):
"""RSSフィードを取得して記事リストを返す"""
# URLからXMLを取得
with urllib.request.urlopen(url) as response:
xml_data = response.read()
root = ET.fromstring(xml_data)
articles = []
# 各記事を処理
for item in root.findall('.//item'):
article = {
'title': item.find('title').text,
'link': item.find('link').text,
'pubDate': item.find('pubDate').text,
}
# 説明(オプショナル)
description = item.find('description')
if description is not None:
article['description'] = description.text
articles.append(article)
return articles
# 使い方
articles = parse_rss('https://example.com/feed.xml')
for article in articles:
print(f"{article['title']}: {article['link']}")
例3:CSVからXMLへの変換
CSVファイルのデータをXML形式に変換するケース:
import xml.etree.ElementTree as ET
import csv
def csv_to_xml(csv_filename, xml_filename):
"""CSVファイルをXML形式に変換"""
# ルート要素
root = ET.Element('employees')
# CSVを読み込む
with open(csv_filename, 'r', encoding='utf-8') as f:
reader = csv.DictReader(f)
for row in reader:
# 各行を<employee>要素に
employee = ET.SubElement(root, 'employee', id=row['id'])
ET.SubElement(employee, 'name').text = row['name']
ET.SubElement(employee, 'department').text = row['department']
ET.SubElement(employee, 'salary').text = row['salary']
# XMLとして保存
tree = ET.ElementTree(root)
tree.write(xml_filename, encoding='utf-8', xml_declaration=True)
print(f'{csv_filename} を {xml_filename} に変換しました')
# 使い方
csv_to_xml('employees.csv', 'employees.xml')
例4:XMLの整形(インデント追加)
ElementTreeで保存したXMLは改行やインデントがないので、読みにくいことがあります。整形する方法:
import xml.etree.ElementTree as ET
def prettify_xml(element, level=0):
"""XMLを人間が読みやすい形に整形"""
indent = "\n" + " " * level
if len(element):
if not element.text or not element.text.strip():
element.text = indent + " "
if not element.tail or not element.tail.strip():
element.tail = indent
for child in element:
prettify_xml(child, level + 1)
if not child.tail or not child.tail.strip():
child.tail = indent
else:
if level and (not element.tail or not element.tail.strip()):
element.tail = indent
# 使い方
tree = ET.parse('books.xml')
root = tree.getroot()
prettify_xml(root)
tree.write('books_pretty.xml', encoding='utf-8', xml_declaration=True)
よくあるエラーと対処法

ElementTreeを使っていると、いくつか典型的なエラーに遭遇します。対処法を知っておきましょう。
エラー1:ParseError
エラーメッセージ:
xml.etree.ElementTree.ParseError: not well-formed (invalid token)
原因:
XMLの構文が間違っている(タグの閉じ忘れ、特殊文字の処理ミスなど)
対処法:
- XMLファイルの構文を確認する
- オンラインのXMLバリデーター(検証ツール)を使って確認
- エラーメッセージに表示される行番号を確認
try:
tree = ET.parse('broken.xml')
except ET.ParseError as e:
print(f'XML解析エラー: {e}')
# エラー時の処理
エラー2:AttributeError
エラーメッセージ:
AttributeError: 'NoneType' object has no attribute 'text'
原因:find()やfindall()で要素が見つからず、Noneに対して.textなどを呼び出している
対処法:
存在チェックを必ず行う
# 悪い例
title = book.find('title').text # titleが存在しないとエラー
# 良い例
title_element = book.find('title')
if title_element is not None:
title = title_element.text
else:
title = '(タイトルなし)'
エラー3:UnicodeEncodeError
エラーメッセージ:
UnicodeEncodeError: 'ascii' codec can't encode characters
原因:
日本語などの非ASCII文字を含むXMLを正しくエンコードせずに保存している
対処法:encoding='utf-8'を必ず指定する
# 正しい保存方法
tree.write('output.xml', encoding='utf-8', xml_declaration=True)
エラー4:FileNotFoundError
エラーメッセージ:
FileNotFoundError: [Errno 2] No such file or directory: 'data.xml'
原因:
指定したファイルが存在しない、またはパスが間違っている
対処法:
ファイルの存在を確認してから処理する
import os
xml_file = 'data.xml'
if os.path.exists(xml_file):
tree = ET.parse(xml_file)
else:
print(f'{xml_file} が見つかりません')
ElementTreeを使う時のベストプラクティス
実務で使う時に知っておきたい、より良い使い方のコツをご紹介します。
1. 名前空間の扱い
XMLで名前空間(namespace)が使われている場合の対処法:
# 名前空間付きのXML
xml_string = '''
<root xmlns:custom="http://example.com/custom">
<custom:item>データ</custom:item>
</root>
'''
root = ET.fromstring(xml_string)
# 名前空間を辞書で定義
namespaces = {'custom': 'http://example.com/custom'}
# 検索時に名前空間を指定
items = root.findall('custom:item', namespaces)
for item in items:
print(item.text)
2. 大きなXMLファイルの処理
メモリ効率を考えた処理方法:
import xml.etree.ElementTree as ET
# iterparse を使うとメモリ効率が良い
for event, element in ET.iterparse('huge_file.xml', events=('end',)):
if element.tag == 'book':
title = element.find('title').text
print(title)
# 処理済みの要素をメモリから解放
element.clear()
iterparse()を使うと、ファイル全体を一度にメモリに読み込まず、必要な部分だけ処理できます。
3. デフォルト値の設定
要素が見つからない時のデフォルト値を設定する書き方:
def get_text(element, tag, default=''):
"""要素からテキストを取得、なければデフォルト値を返す"""
found = element.find(tag)
return found.text if found is not None else default
# 使い方
for book in root.findall('book'):
title = get_text(book, 'title', '(タイトルなし)')
price = get_text(book, 'price', '0')
print(f'{title}: {price}円')
4. 複数の条件での検索
より複雑な検索をする方法:
# 価格が2000円以上でカテゴリがfictionの本
expensive_fiction = []
for book in root.findall('book'):
if book.get('category') == 'fiction':
price = int(book.find('price').text)
if price >= 2000:
expensive_fiction.append(book)
print(f'{len(expensive_fiction)}冊見つかりました')
まとめ:ElementTreeでXML処理をマスターしよう
Python ElementTreeは、XMLを扱うための強力で使いやすいツールです。
この記事のポイントをおさらい:
- ElementTreeはPython標準ライブラリで追加インストール不要
ET.parse()でファイル、ET.fromstring()で文字列から読み込みfind()、findall()で要素を検索できる.textでテキスト、.get()で属性を取得- XPathを使うとより柔軟な検索が可能
ET.Element()とSubElement()で新規作成- 要素の存在チェック(
if element is not None)が重要 encoding='utf-8'を指定して保存する
設定ファイル、データ交換、WebAPIのレスポンス処理など、XMLが必要な場面は多岐にわたります。ElementTreeをマスターすれば、これらの処理が簡単にできるようになりますよ。
最初は少し複雑に感じるかもしれませんが、基本的な操作から始めて徐々に慣れていけば大丈夫です。実際に手を動かしながら、XMLとElementTreeの使い方を身につけていってくださいね!

コメント