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,即使是複雜條件也能直覺地提取資料。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 的格式化,確認語法錯誤 進行特殊字元(例如:&
→ &
)的轉換 範例:錯誤的 XML <note>
<text>5 & 3</text>
</note>
修正後: <note>
<text>5 & 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 的 ElementTree
或 lxml
會自動讀取此宣告,但 開啟檔案時若字元碼不一致,就會發生錯誤。 日文的 XML 檔案有時會使用 Shift_JIS
或 EUC-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. lxml
和 ElementTree
應該使用哪一個? 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 的技術,將成為在廣泛領域中實用的技能 。