【Python xml】初心者向けにXML解析と生成を徹底解説

はじめに

Pythonは、さまざまなデータフォーマットを扱ううえで便利なプログラミング言語です。
とくに構造化されたデータを表現することが多い XML は、Pythonで効率よく解析・生成ができます。
実務においては、設定ファイルをXML形式で管理しているプロジェクトや、外部システムとのデータ連携でXMLを取り扱うケースもよくあるかもしれません。
本記事では Python xml の活用方法に焦点をあて、初心者でも理解しやすいようにポイントを押さえながら解説していきます。

XMLはデータの階層構造を示すために柔軟性があり、Webサービスや構成ファイルとして利用されることが多いです。
一方で、「どのようにタグを読み取って情報を取り出すのか」「属性やネームスペースはどう扱うのか」といった疑問が浮かぶこともあるでしょう。
Pythonには標準モジュールや外部ライブラリが存在しており、これらを使うことでスムーズにXMLを取り扱うことができます。

ここでは xml.etree.ElementTree などの標準モジュールを中心に、基本的な解析・編集の方法を紹介します。
また、XMLを新規に生成するときのポイントや、要素を追加・更新するときのテクニックなども説明し、実務シーンを意識しながら進めていきます。

この記事を読むとわかること

  • PythonでXMLを解析する基本的な方法
  • PythonでXMLを生成する手順
  • 実務の活用シーンと結びつけた具体例
  • タグや属性、ネームスペースなどの考え方
  • XMLを扱うときの注意点とちょっとしたコツ

PythonでXMLを扱うメリット

PythonとXMLを組み合わせるメリットは多くあります。
まず、標準ライブラリにXMLを扱う機能が含まれているため、追加のインストール作業を省ける点が挙げられます。
さらに、Pythonのシンプルな文法のおかげで、XMLの解析から生成までのコードを読みやすく書けるのも魅力的です。

一方でJSONを使うプロジェクトも増えていますが、複雑な構造をもつデータを可読性よく表現する場合や、レガシーシステムとの連携などでは、いまだにXMLが広く使われています。
たとえば、ネットワーク機器の設定や一部のWeb APIでは、XMLが標準のフォーマットとして利用されているケースがあるでしょう。
こうした現場で作業するとき、Pythonの標準ライブラリがあれば余計なセットアップなしに作業を始められます。

XMLの基本的な構造とは

XMLはタグ(要素)と属性、階層構造をもつテキストデータ形式です。
例えば以下のような構造があります。

<users>
    <user id="101">
        <name>Taro</name>
        <email>taro@example.com</email>
    </user>
    <user id="102">
        <name>Hanako</name>
        <email>hanako@example.com</email>
    </user>
</users>

<users> 要素の中に複数の <user> 要素があり、それぞれが <name><email> といったタグを内包しています。
id のように要素の属性としてデータを持たせることも可能です。
親要素の下に子要素をネストすることで、階層的にデータを表現できるのがXMLの特徴です。

実務の現場では、設定ファイルにユーザー情報やシステム設定のようなデータが入っている場合があります。
Pythonからそれらのファイルを読み取り、必要に応じて編集・再保存すれば、データの一括管理や自動生成がスムーズになります。

PythonでXMLを読み込む主な方法

ElementTreeモジュール

標準ライブラリの xml.etree.ElementTree が最もよく使われる方法でしょう。
ファイルの読み込み、要素の抽出、属性の取得、タグの更新など、一連の操作を一通りカバーしています。

import xml.etree.ElementTree as ET

# XMLファイルを読み込む
tree = ET.parse("example.xml")
root = tree.getroot()

# ルート要素のタグ名を表示
print(root.tag)

# 子要素を反復処理
for user in root:
    # タグ名と属性の取得
    print(user.tag, user.attrib)
    
    # さらに子要素を取り出し
    for child in user:
        print(child.tag, child.text)

上記のコードでは、parse() でXMLファイルを読み込んでから、 getroot() でルート要素を取得しています。
その後、ルート要素 (root) の下にある子要素をループしながら、タグ名と属性を確認しています。
テキストの中身は child.text で取得できるため、要素の中身を楽に取り出せるでしょう。

実務において、例えばユーザー管理に関連するXMLファイルがあるときは、このようにルートから要素をたどって情報を整理します。
ID属性を見て特定のユーザーを探す処理なども行いやすく、ロジックが見えやすいのがメリットです。

エラーハンドリングとファイル管理

XMLファイルが壊れていたり、要素の記述が不完全だったりする場合はパースエラーが起こる可能性があります。
このときは try-except でエラーハンドリングを行い、安全にプログラムを進める設計がよく行われます。
たとえば、通信が不安定な場所からデータを取得してくる際などには、ファイルが壊れている前提で例外処理を入れておくと安心です。

import xml.etree.ElementTree as ET

try:
    tree = ET.parse("example.xml")
    root = tree.getroot()
    # ここでさらに処理
except ET.ParseError:
    print("XMLのパースに失敗しました。ファイルが正しい形式か確認してください。")
except FileNotFoundError:
    print("指定されたXMLファイルが見つかりませんでした。")

ファイルが存在しない場合の例外は FileNotFoundError をキャッチしておくと、ユーザーにも状況を説明しやすいです。
実務では、ファイル名の指定ミスやディレクトリの構成変更などによってファイルパスが合わなくなることもあります。
こうしたトラブルを早期に発見できるよう、適切に例外処理を配置すると安心でしょう。

XML要素へのアクセス方法

タグ名や属性で要素を検索する

XMLを扱うときは、特定のタグを検索したり、属性値でフィルタリングしたりするケースがよくあります。
たとえば、ElementTreeでは find()findall() を使って、下位要素を取得できます。

import xml.etree.ElementTree as ET

tree = ET.parse("example.xml")
root = tree.getroot()

# 特定のタグ名を検索
specific_user = root.find("user")
if specific_user is not None:
    print(specific_user.tag, specific_user.attrib)

# 複数要素をまとめて取得
all_users = root.findall("user")
for user in all_users:
    print("ID属性:", user.get("id"))
    name = user.find("name").text
    email = user.find("email").text
    print("Name:", name, "Email:", email)

find() は最初にヒットした要素を返し、 findall() はすべての要素をリストとして返します。
このとき、 root.findall("user") のようにタグ名を直接指定してもいいですし、 ".//user" のように 階層をまたいで検索 する指定もできます。
実務ではXMLの構造が深くネストしていることもあるため、 ".//" の指定で階層を問わずタグを見つけるのは便利です。

また、属性は element.get("属性名") で取得できるので、ユーザーIDなどを基準に処理したいときに役立ちます。
例えば「IDが101のuserタグだけ処理したい」といった場合も柔軟に実装できるでしょう。

Xpath表記を活用する

さらに詳細な要素の取得を行いたい場合は、ElementTreeでXPATHの簡易的な指定ができます。
あまりに複雑な検索を行うと処理がわかりにくくなるので、実務では過度に深いパス指定は避けることも大切です。
しかし、データ構造が明確である場合は、XPATH風の指定が素早いこともあります。

all_emails = root.findall("./user/email")
for email in all_emails:
    print(email.text)

ここでは ./user/email という指定で、 <user> の子要素としての <email> を抽出しています。
データの階層が増えても同様の考え方で取り出せるため、条件に合った要素だけをフィルタリングするのに適しています。

XMLの編集と更新

要素や属性の追加

読み込んだXMLを編集する場合も、ElementTreeを使えばスムーズです。
例えば新しい <user> 要素を追加したいときは、Elementオブジェクトを生成してルート要素にappendします。

import xml.etree.ElementTree as ET

tree = ET.parse("example.xml")
root = tree.getroot()

# 新しい要素を作成
new_user = ET.Element("user", attrib={"id": "103"})
name_elem = ET.SubElement(new_user, "name")
name_elem.text = "Ken"
email_elem = ET.SubElement(new_user, "email")
email_elem.text = "ken@example.com"

# ルートに追加
root.append(new_user)

# ファイルに書き戻し
tree.write("example.xml", encoding="utf-8", xml_declaration=True)

上記のように、ET.Element() で新しい要素を作成し、必要に応じてサブ要素(ET.SubElement())を付与していきます。
最後に tree.write() で同じファイル名に書き込みを行えば、XMLが更新されて保存されます。

もし別のファイル名で保存したい場合は、 "new_example.xml" のように指定して、オリジナルファイルを残しておくことも可能です。
実務ではバックアップをとってから上書きするなどの手法があるので、編集手順には注意しましょう。

要素の削除・変更

既存の要素を削除したり、属性を変更する場合も同様に操作できます。
例えばすでに読み込んだ <user> 要素のID属性を変更したり、<user> 要素自体をルートから削除するイメージです。

all_users = root.findall("user")

# 特定のID属性をもつ要素を削除
for user in all_users:
    if user.get("id") == "102":
        root.remove(user)

# 別の要素の属性を変更
if all_users:
    first_user = all_users[0]
    first_user.set("id", "999")

tree.write("example.xml", encoding="utf-8", xml_declaration=True)

上記の例では、root.remove(user) で要素自体を削除しています。
属性の更新は element.set("属性名", "値") で行えるので、IDやステータスを切り替えたいときに有用でしょう。

PythonでXMLを新規生成する流れ

ゼロからファイルを作る

前述したように、XML要素を生成してサブ要素を付与し、最後に書き込むだけです。
以下では新規に <users> のルート要素を作り、複数の <user> 要素を追加してファイルを保存する例を示します。

import xml.etree.ElementTree as ET

# ルート要素を作成
root = ET.Element("users")

# ユーザーリスト
data = [
    {"id": "201", "name": "Satoshi", "email": "satoshi@example.com"},
    {"id": "202", "name": "Mika", "email": "mika@example.com"}
]

for user_info in data:
    user_elem = ET.Element("user", attrib={"id": user_info["id"]})
    name_elem = ET.SubElement(user_elem, "name")
    name_elem.text = user_info["name"]
    email_elem = ET.SubElement(user_elem, "email")
    email_elem.text = user_info["email"]
    root.append(user_elem)

# ツリーを生成してファイルに書き込む
tree = ET.ElementTree(root)
tree.write("new_users.xml", encoding="utf-8", xml_declaration=True)

このコードを実行すると、 new_users.xml<users> ルートを持つXMLファイルが生成されます。
実務ではCSVやJSONからデータを読み込んで、その内容をXMLに変換するといった処理を組むケースもあるでしょう。

XML宣言 ( <?xml version="1.0"?> ) が欲しい場合、tree.write() の引数で xml_declaration=True を指定すれば出力されます。
日本語などマルチバイト文字を含むときは、encoding="utf-8" をつけておくと文字化けを防ぎやすいです。

ネームスペースの扱い

実際のプロジェクトではXMLにネームスペースが含まれている場合があります。
例えば xmlns 属性を持つタグは、要素名に特定の名前空間が紐づけられている形です。

<root xmlns="http://example.com/schema">
    <child>Hello</child>
</root>

ElementTreeではネームスペースを認識するために、要素名にURIを含めた形でアクセスする必要があります。
例えば "{http://example.com/schema}child" のように書くと、その名前空間下の <child> を検索可能です。
ここは初心者には少しとっつきにくいかもしれません。
しかし、多くの業務システムや外部サービスのAPIではこのネームスペースが利用されることがあります。
混乱を避けるためにも、実務ではネームスペースの有無を事前に把握してから開発するとスムーズでしょう。

PythonでXMLを扱う実務例

設定ファイルとしての利用

XML形式でシステムの設定を管理するケースは珍しくありません。
例えば以下のような config.xml があるとします。

<config>
    <database host="localhost" port="5432">
        <username>admin</username>
        <password>secret</password>
    </database>
    <features>
        <feature name="logging" enabled="true" />
        <feature name="analytics" enabled="false" />
    </features>
</config>

Pythonからこれを読み込み、データベース接続に必要な情報を取得したり、機能の有効/無効を切り替えたりできます。
実務では環境ごとに設定ファイルを使い分けて、動的に値を切り替える仕組みが便利です。
特にクラウド環境や複数のサーバーを運用している場合、XMLファイルを一括で編集して管理するだけで、全体の設定が整合性を保ちやすくなるでしょう。

外部システムとのデータ連携

外部APIやレガシーシステムとの通信でXMLを使うケースもあります。
例えばSOAPベースのWebサービスはXMLメッセージをやり取りすることが多いです。
PythonでXMLを生成し、リクエストを送信してレスポンスを解析すれば、外部システムとの連携が可能になるでしょう。

ただし、SOAPの場合は独特のネームスペース指定やメッセージ形式があり、単純なDOM操作だけでは理解しづらいこともあります。
このような場合は、ElementTreeを活用しつつXML構造を確認しながら少しずつ開発を進めると確実です。
実際の運用でファイルサイズが大きい場合は、ストリーム形式で逐次パースする方法を検討することもあります。

RSSやATOMのフィード解析

ブログやニュースサイトなどから情報を取得する手段として、RSSやATOMフィードを読み込むことがあります。
これらのフィードはXML形式で配信されるため、Pythonで取得して解析すれば、自動収集や自動分析ができます。

import requests
import xml.etree.ElementTree as ET

url = "https://example.com/feed"
response = requests.get(url)
root = ET.fromstring(response.content)

for item in root.findall(".//item"):
    title = item.find("title").text
    link = item.find("link").text
    print("タイトル:", title)
    print("リンク:", link)

上記の例のように、外部サイトのフィードを requests ライブラリで取得し、 ET.fromstring() を使って文字列からXML解析を行います。
あとはタイトルやリンクを取り出し、まとめて保存したり、通知を送ったりなどの活用が考えられるでしょう。
実務で大量のRSSを巡回して情報収集したい場合にも、Python+XMLの組み合わせが有用です。

XMLと他形式(JSONなど)の比較

最近では JSON が人気を集めており、APIなどでよく採用されています。
一方で、XMLは階層が深くても明確にタグで囲める点や、属性で補足情報を載せやすい点が特徴です。
大量のデータを機械的に扱うときは、どちらのフォーマットが適切かを見極める必要があります。

実務では「外部サービスがXMLのみを受け付ける」というケースもあるため、選択の余地なくXMLを扱わなければならない局面が存在します。
PythonでXMLをしっかり扱えるようになっておくと、汎用的なスキルとして重宝するでしょう。

また、JSONへの変換処理を入れたい場合は、一度XMLをパースしてPythonの辞書やリスト形式に変換し、その後 json モジュールで出力する方法がよく取られます。
このように Python xml は他フォーマットへのブリッジとしても役立つわけです。

さまざまなライブラリの選択肢

標準ライブラリ以外にも、 lxmlminidomxmltodict など多様な選択肢があります。
lxmlはパフォーマンスやXPath機能が豊富で、ネームスペースを含む複雑なXMLを高速に扱いやすい点が人気です。
xmltodictはXMLを辞書形式として操作する発想を持っており、JSONに慣れている方にはとっつきやすい可能性があります。

ただし、初心者が最初に触れるのであれば、まずはElementTreeで基本を学んでから、必要に応じて外部ライブラリを検討するのがよいでしょう。
企業のサーバーに外部ライブラリのインストール権限がないケースもあるため、まずは標準ライブラリで完結できるのは大きなメリットです。

注意点とベストプラクティス

PythonでXMLを扱う際には、いくつかの注意点があります。
まず、要素や属性名、階層の指定が正しくないと予想外の結果が返ってくる可能性があります。
構造が複雑なXMLでは、どのタグがどのようにネストされているかを事前に把握しておくことが大事です。

また、大規模なファイルを読み込む場合、単純に ET.parse() を使うとメモリに大きな負荷がかかることもあります。
このような場合は、 iterparse を使い、イベントドリブンに要素が読み込まれるたびに処理する方法があります。
ログ解析や膨大なデータファイルの取り扱いなどは、こうした最適化を検討したほうが安全です。

巨大なファイルを扱うなら、一括読み込みではなくストリームパースを検討すると良いです。
要素単位で処理すればメモリ使用量を抑えながら必要な部分のみを取り出せます。

実務では、セキュリティ上の理由から外部から取得したXMLにエンティティを展開することを禁止するケースもあります。
XML External Entity (XXE) 攻撃と呼ばれる手法で、不正にファイル内容を読み取られたりする可能性が指摘されているためです。
安全面に配慮してライブラリの設定をカスタマイズすることも検討すべきでしょう。

Python xmlと実務の結びつき

ここまで紹介してきたように、PythonでXMLを扱う方法は多岐にわたります。
実務では、設定ファイルの管理、外部APIとの連携、RSSフィードの解析、文書データの自動生成など、多彩なシーンで役立ちます。

例えば、システム移行のプロジェクトで、既存システムからXMLファイルを受け取って新システムにデータを登録する場合があるとします。
その際にPythonを使ってXMLを一括でパースし、不要なタグを削除したり、形式を変換してからデータベースに保存する、という流れが考えられるでしょう。
あるいは、ECサイトの在庫情報をXMLでやり取りしている場合に、外部倉庫のシステムと連携する処理の中でXML解析を組み込む、といった具合です。

Python xml をマスターしておけば、こうした場面でも素早く対応できるはずです。
必要に応じてXPathやネームスペースについてもう少し深掘りし、規模や要件に合った方法を選択できるようになると、さらに応用が効きやすくなります。

エラー処理とデバッグのヒント

XMLが正しいフォーマットであることを前提にしても、実務ではさまざまな原因でエラーが発生することがあります。
ファイルに余計な文字が混入したり、エンコードが異なるファイルが混在していると文字化けが起こるかもしれません。

こうした状況を避けるには、デバッグ用にXML文字列を印字して構造を確認する、あるいは開発段階でスキーマやDTDを用いてXMLを検証する手法が存在します。
ただし、初心者向けにはスキーマの話題はやや高度ですが、整合性を保つためにXMLの形式を検証することは大事だと覚えておくとよいでしょう。

実運用に入る前に、できるだけ多くのパターンのテストデータでパースや生成を試してみると、予期せぬ問題の早期発見につながります。
文字化けやタグの抜け漏れ、要素の順序による影響などに対応しやすくなるはずです。

本番環境のファイルを編集するときは、必ずバックアップをとるかテスト環境を用意してから実行したほうが安心です。
万が一誤った編集をしてしまうと、システム全体に影響が出る可能性があります。

まとめ

XMLは古くから使われてきたデータ形式であり、現在でも設定ファイルや外部システムとの連携でよく見かけます。
Pythonには xml.etree.ElementTree をはじめとする標準ライブラリが用意されており、わざわざ追加インストールしなくてもXML解析・生成を行えます。

最初は単純なXMLファイルを読み込んでみて、要素や属性を取得するところから始めると理解が深まりやすいでしょう。
要素の追加や削除などを覚えると、実務で設定ファイルの自動書き換えなども楽にできるようになります。

実際の職場で大量のファイルを扱う場合や、SOAPなどのプロトコルを扱う場合、あるいはネームスペースが絡むXMLを扱う場合には、もう少し踏み込んだ知識が必要です。
しかし、その基礎となる部分はElementTreeで十分学べます。
XMLの特徴やPythonのメリットを理解し、必要に応じてライブラリを選択するとよいでしょう。

Python xmlを身につけることは、データ処理の幅を広げ、さまざまな現場で活躍するスキルにつながります。
XML以外にもJSONなどのフォーマットに触れながら、自分のプロジェクトに合ったデータ処理を行ってみてください。
これによって、データ連携や構成管理といった作業を効率的に進めやすくなるはずです。

Pythonをマスターしよう

この記事で学んだPythonの知識をさらに伸ばしませんか?
Udemyには、現場ですぐ使えるスキルを身につけられる実践的な講座が揃っています。