【適合初學者】Python讀取XML方法彙整|ElementTree・lxml使用與範例

1. 在使用 Python 讀取 XML 之前需要知道的事項

使用 Python 處理 XML 的場合是什麼?

Python 是一種廣泛用於多種用途的通用程式語言,其中「讀取 XML 檔案」是資料處理現場中常用的一項技術。特別是在以下情況下,需要使用 Python 讀取 XML。
  • 想要解析從 Web API 取得的 XML 資料
  • 想要處理從其他系統匯出的 XML 檔案
  • 想要讀取作為設定檔案使用的 XML
XML 透過標籤結構可以明確表達資料的階層和意義,因此在各種產業中被廣泛使用。使用 Python,就可以輕鬆讀取、加工和解析這些 XML 資料。

XML 是什麼?簡單回顧

XML(Extensible Markup Language)是一種可以靈活定義資料結構的標記語言。雖然結構類似 HTML,但用途不同。HTML 用於「外觀(顯示)」,而 XML 是用來描述「資料結構和意義」的格式。 例如,以下這種形式是典型的 XML:
<book>
  <title>Python 入門</title>
  <author>Yamada Tarō</author>
  <price>2800</price>
</book>
要讀取並使用這種形式的資料,需要使用專用的程式庫。

介紹用於在 Python 中讀取 XML 的程式庫

Python 中,標準程式庫和外部程式庫提供了幾種讀取 XML 的方法。代表性的如下。
  • xml.etree.ElementTree(標準程式庫)
  • xml.dom.minidom(標準程式庫)
  • lxml(外部程式庫,支援 XPath 和驗證)
本文將使用這些程式庫,以附帶範例程式碼的方式,清楚說明在 Python 中讀取 XML 檔案的方法。即使是初學者也能輕鬆閱讀,我們將從基礎開始仔細介紹,請放心。

2. 使用 Python 讀取 XML 的基本知識

使用 ElementTree 讀取 XML 檔案

首先,使用實際的 XML 檔案,讓我們看看使用 ElementTree 讀取的方法。 範例 XML(sample.xml):
<books>
  <book>
    <title>Python 入門</title>
    <author>Yamada Taro</author>
    <price>2800</price>
  </book>
  <book>
    <title>AI 的未來</title>
    <author>Suzuki Ichiro</author>
    <price>3500</price>
  </book>
</books>
Python 程式碼:
import xml.etree.ElementTree as ET

# 讀取 XML 檔案
tree = ET.parse('sample.xml')
root = tree.getroot()

# 確認根元素標籤
print(f"根元素: {root.tag}")

# 迴圈處理每個 book 元素
for book in root.findall('book'):
    title = book.find('title').text
    author = book.find('author').text
    price = int(book.find('price').text)

    print(f"標題: {title}, 作者: {author}, 價格: {price}日圓")
執行結果:
根元素: books
標題: Python 入門, 作者: Yamada Taro, 價格: 2800日圓
標題: AI 的未來, 作者: Suzuki Ichiro, 價格: 3500日圓
就像這樣,使用 ElementTree.parse() 讀取 XML 檔案,使用 getroot() 取得根元素,然後使用 find()findall() 抽出必要的元素,這就是基本的流程。

從字串讀取 XML 的方法

XML 不是檔案而是字串的情況也時有發生。那樣的情況下,使用 ET.fromstring() 來解析。 範例:
xml_data = '''
<user>
  <name>Sagawa Shota</name>
  <email>sagawa@example.com</email>
</user>
'''

root = ET.fromstring(xml_data)

name = root.find('name').text
email = root.find('email').text

print(f"姓名: {name}, 電子郵件: {email}")
同樣地,從根元素使用 find() 取得必要子元素並取出值。

屬性的取得與文字的處理

XML 元素中,有時會在標籤內定義屬性。在 Python 中,可以使用 .attrib 來存取。 範例(帶屬性的 XML):
<user id="101">
  <name>Sagawa Shota</name>
</user>
Python 程式碼:
root = ET.fromstring('''
<user id="101">
  <name>Sagawa Shota</name>
</user>
''')

print(f"使用者 ID: {root.attrib['id']}")

3. 其他 XML 解析函式庫的介紹

minidom:基於 DOM 的標準函式庫

xml.dom.minidom 是 Python 標準包含的 XML 解析器,基於 W3C 的 DOM(Document Object Model)規格來處理 XML。 與 ElementTree 相比,有時會給人較難處理的印象,但如果想細緻操作節點的種類或結構,則很方便。 範例:
from xml.dom import minidom

xml_data = '''
<user>
  <name>Sagawa Shota</name>
  <email>sagawa@example.com</email>
</user>
'''

dom = minidom.parseString(xml_data)
name = dom.getElementsByTagName('name')[0].firstChild.nodeValue
email = dom.getElementsByTagName('email')[0].firstChild.nodeValue

print(f"名字: {name}, 電子郵件: {email}")
特點與優點:
  • 容易存取細部的節點結構
  • 屬性或子節點的類型明確分類
  • 容易將 XML 格式化輸出(pretty print)
缺點:
  • 程式碼容易變得冗長
  • 不適合處理大型 XML(記憶體消耗大)

lxml:高速且強大的外部函式庫

lxml 是以 C 語言為基礎實作的高速 XML 解析器,對應 XPath 或 XSLT 等進階 XML 功能。由於提供類似 ElementTree 的 API,學習成本也較低。 安裝方法:
pip install lxml
基本用法:
from lxml import etree

xml_data = '''
<books>
  <book>
    <title>Python 實踐</title>
    <price>3000</price>
  </book>
</books>
'''

root = etree.fromstring(xml_data)
title = root.xpath('//book/title/text()')[0]
price = root.xpath('//book/price/text()')[0]

print(f"標題: {title}, 價格: {price}日圓")
特點與優點:
  • 可以使用 XPath,因此能進行彈性的搜尋
  • 高速,適合大量 XML 處理
  • 也具備與 HTML 的相容性,可應用於網頁抓取
缺點:
  • 需要安裝外部函式庫
  • 需要一些初始學習(XPath 等)

函式庫的選擇方式總結

函式庫特點適合的案例
ElementTree可標準使用,能進行基本的讀寫小型・中型 XML 的讀取
minidom擅長 DOM 操作,格式化輸出想細緻操作節點結構時
lxml高速・XPath 對應,彈性高大型資料,需要進階搜尋時

4. 實用的範例程式碼

本節將以接近實際業務或資料處理的形式,實踐性地介紹使用 Python 讀取 XML 的處理方式。具體來說,將展示對應常用模式如「多個節點的重複處理」「依條件過濾」「寫入 XML 檔案」等的程式碼範例。

多個節點的重複處理

當 XML 內重複出現相同結構的資料(例如多個 <book> 元素)時,使用 findall() 進行迴圈處理。 範例 XML:
<books>
  <book>
    <title>Python 入門</title>
    <author>Yamada Tarō</author>
    <price>2800</price>
  </book>
  <book>
    <title>AI 的未來</title>
    <author>Suzuki Ichirō</author>
    <price>3500</price>
  </book>
</books>
Python 程式碼(使用 ElementTree):
import xml.etree.ElementTree as ET

 tree = ET.parse('books.xml')
 root = tree.getroot()

 for book in root.findall('book'):
     title = book.find('title').text
     author = book.find('author').text
     price = int(book.find('price').text)

     print(f"標題: {title}, 作者: {author}, 價格: {price} 日圓")
透過在迴圈內存取個別元素,即可從 XML 中提取資料並進行處理。

依條件的過濾

接下來,介紹僅提取價格 3000 日圓以上的書籍的條件處理方式。 Python 程式碼:
for book in root.findall('book'):
    price = int(book.find('price').text)
    if price >= 3000:
        title = book.find('title').text
        print(f"高額書籍: {title}({price} 日圓)")
透過結合 if 陳述式,即可處理符合任意條件的元素。

寫入 XML 檔案(儲存)

對讀取的 XML 進行修改後,以新檔案形式儲存的情境也很常見。 寫出範例:
# 建立新的根元素
root = ET.Element('users')

# 新增子元素
user1 = ET.SubElement(root, 'user', attrib={'id': '1'})
ET.SubElement(user1, 'name').text = 'Sagawa Shōta'
ET.SubElement(user1, 'email').text = 'sagawa@example.com'

# 以樹狀結構儲存
tree = ET.ElementTree(root)
tree.write('users.xml', encoding='utf-8', xml_declaration=True)
由此,將產生以下的 XML 檔案:
<?xml version='1.0' encoding='utf-8'?>
<users>
  <user id="1">
    <name>Sagawa Shōta</name>
    <email>sagawa@example.com</email>
  </user>
</users>

應用:使用 XPath 提取(lxml)

若使用 lxml,則可進行更靈活且強大的搜尋。
from lxml import etree

 tree = etree.parse('books.xml')
 titles = tree.xpath('//book[price >= 3000]/title/text()')

 for title in titles:
     print(f"高額書籍標題: {title}")
活用 XPath,即使是複雜條件也能直覺地提取資料。
RUNTEQ(ランテック)|超実戦型エンジニア育成スクール

5. 常見錯誤與對策

在 Python 中讀取 XML 時,可能會發生語法錯誤或字元編碼問題等各種錯誤。本節將介紹初學者容易遇到的典型錯誤及其對策。

UnicodeDecodeError:因字元編碼差異導致的讀取失敗

錯誤內容:
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x93 in position 10
原因: 如果 XML 檔案是以 UTF-8 以外的字元編碼(例如 Shift_JIS 或 UTF-16)儲存,Python 無法正確解碼就會發生錯誤。 對策: 在讀取檔案時明確指定編碼。
with open('sample.xml', encoding='shift_jis') as f:
    data = f.read()

import xml.etree.ElementTree as ET
root = ET.fromstring(data)
或者,直接以二進位模式傳遞給 ElementTree.parse() 的方法也有效。

ParseError:XML 語法不正確

錯誤內容:
xml.etree.ElementTree.ParseError: not well-formed (invalid token): line 3, column 15
原因: 如果 XML 檔案中的標籤未關閉、特殊字元(例如:&)未轉義、存在語法錯誤等情況,就會發生。 對策:
  • 從錯誤訊息中特定對應的行號和欄位
  • 使用編輯器顯示 XML 的格式化,確認語法錯誤
  • 進行特殊字元(例如:&&amp;)的轉換
範例:錯誤的 XML
<note>
  <text>5 & 3</text>
</note>
修正後:
<note>
  <text>5 &amp; 3</text>
</note>

NoneType Attribute Error:存取不存在的元素

錯誤內容:
AttributeError: 'NoneType' object has no attribute 'text'
原因: 如果指定的標籤在 XML 中不存在,find() 會返回 None,直接存取 .text 就會發生錯誤。 對策: 在取得值之前檢查元素是否存在。
title_elem = book.find('title')
if title_elem is not None:
    title = title_elem.text
else:
    title = '標題不明'
或者,如果是 Python 3.8 以上,可以使用 Walrus 運算子(:=)來簡潔地撰寫。
if (title_elem := book.find('title')) is not None:
    print(title_elem.text)

XML 檔案損壞或為空的情況

症狀:
  • 雖然沒有錯誤,但 getroot() 返回 None
  • findall() 無法取得任何東西
原因:
  • XML 檔案為空(0 位元組)
  • 資料中途截斷(下載失敗等)
對策:
  • 確認檔案大小和內容
  • 使用 XML 驗證工具進行語法檢查
  • 檢討下載來源或產生來源的處理

6. 常見問題(FAQ)

本節中,我們將以問答形式,清楚解說那些想「用 Python 讀取 XML」的讀者常提出的疑問與不安。內容著重於事先解決實務或學習中容易卡住的要點。

Q1. XML 檔案的編碼(字元碼)該如何處理?

A. XML 檔案通常在最上方有以下類似的編碼指定:
<?xml version="1.0" encoding="UTF-8"?>
Python 的 ElementTreelxml 會自動讀取此宣告,但 開啟檔案時若字元碼不一致,就會發生錯誤。 日文的 XML 檔案有時會使用 Shift_JISEUC-JP,因此以下方式明確指定編碼較為安全:
with open('sample.xml', encoding='shift_jis') as f:
    data = f.read()
此外,使用 lxml 可以更靈活地處理編碼。

Q2. 處理大型 XML 檔案時會發生記憶體不足該怎麼辦?

A. 一舉讀取大型 XML 會將全部展開到記憶體,因此處理會變慢或發生錯誤的可能性。 這種情況下,使用能逐次讀取的「迭代器型解析器」會很有效。
import xml.etree.ElementTree as ET

for event, elem in ET.iterparse('large.xml', events=('end',)):
    if elem.tag == 'book':
        print(elem.find('title').text)
        elem.clear()  # 記憶體解放
這種方法可以只依序處理必要部分,從而節省記憶體。

Q3. 不使用 JSON,而是使用 XML 的優點是什麼?

A. 現在許多 API 採用 JSON,但 XML 也有其獨特的優勢。
  • 能嚴格定義階層結構(DTD/XSD 等)
  • 可區分屬性和元素的使用
  • 適合文件導向,適用於設定檔案或組態資訊
  • 在企業或自治體的系統中,XML 仍是主流
也就是說,XML 擅長「定義結構化文件,而非供人閱讀」。依用途而定,未來仍將充分活躍。

Q4. lxmlElementTree 應該使用哪一個?

A. 可依以下標準來區分使用:
函式庫適合的情境
ElementTree小型至中型 XML,使用標準函式庫即足夠的情形
lxml想使用 XPath、希望高速處理、處理大量資料的情形
建議初學者從 ElementTree 開始,但 若想使用 XPath 等進行靈活擷取,或需要處理速度的情形下,lxml 會很強大

7. 總結

在本篇文章中,我們以初學者易懂且適合實務應用的方式,說明了「使用 Python 讀取 XML 的方法」。

使用 Python 讀取 XML 意外地簡單

標準程式庫的 xml.etree.ElementTree 就能在不需特別準備的情況下立即讀取 XML。記住基本的語法和方法(parse()find()findall() 等),就能輕鬆取得和處理資料。

根據用途選擇適當的程式庫很重要

  • 小規模・簡單的處理: ElementTree
  • 細部的節點操作或格式化輸出: minidom
  • 高速處理或 XPath 搜尋: lxml
各個都有優缺點,因此請根據您處理的 XML 大小和目的來選擇使用。

也要為常見的錯誤和問題做好準備

初學者容易跌倒的錯誤,只要了解原因和對策就不會慌張。特別是「字元編碼的差異」或「語法錯誤」、「元素存在檢查」等是常見的。

XML 仍是現役的技術

近年 JSON 的使用增加,但 XML 仍在許多業務系統、行政和資料交換的現場中使用。習得使用 Python 處理 XML 的技術,將成為在廣泛領域中實用的技能
侍エンジニア塾