-
簡介
XML 全稱 Extensible Markup Language,中文譯為可擴展標記語言。
-
XML 之前有兩個先行者:SGML 和 HTML,率先登場的是 SGML, 盡管它功能強大,但文檔結構復雜,既不容易學也不易於使用,因此幾個主要的瀏覽器廠商均拒絕支持 SGML,這些因素限制了 SGML 在網上的傳播性;1989 年 HTML 登場,它繼承了 SGML 諸多優點,去除了 SGML 復雜龐大的缺點,HTML 在數據顯示上表現十分出色,但它的語法是不可擴展的,因此其無法描述數據、可讀性差,沒辦法人們再次將目光轉向 SGML,經過對 SGML 一系列改造,終於在 1998 年,XML 第一個版本問世。
- 簡單來說就是:XML 和 HTML 均由 SGML 改造而來,HTML 是一種頁面技術,聚焦的是數據的顯示,而 XML 易於擴展,主要用來傳送和存儲數據,聚焦的是數據的內容。
-
解析
解析方式
Python 有三種 XML 解析方式:SAX(simple API for XML)、DOM(Document Object Model)、ElementTree。
-
DOM 方式:DOM 中文譯為文檔對象模型,是 W3C 組織推薦的標准編程接口,它將 XML 數據在內存中解析成一個樹,通過對樹的操作來操作 XML。
-
SAX 方式:SAX 是一個用於處理 XML 事件驅動的模型,它逐行掃描文檔,一邊掃描一邊解析,對於大型文檔的解析擁有巨大優勢,盡管不是 W3C 標准,但它卻得到了廣泛認可。
-
ElementTree 方式:ElementTree 相對於 DOM 來說擁有更好的性能,與 SAX 性能差不多,API 使用也很方便。
具體實現
在具體解析之前我們先准備一個 XML,如下所示:
-
- test.xml
-
<?xml version="1.0" encoding="utf-8"?> <list> <student id="stu1" name="stu"> <id>1001</id> <name>張三</name> <age>22</age> <gender>男</gender> </student> <student id="stu2" name="stu"> <id>1002</id> <name>李四</name> <age>21</age> <gender>女</gender> </student> </list>
-
DOM 方式解析
使用 DOM 方式,首先要對其 API 有一定了解,如果不了解,網上的教程也比較多,比如:DOM 教程,下面看一下使用示例。
-
from xml.dom.minidom import parse # 讀取文件 dom = parse('test.xml') # 獲取文檔元素對象 data = dom.documentElement # 獲取 student stus = data.getElementsByTagName('student') for stu in stus: # 獲取標簽屬性值 st_id = stu.getAttribute('id') st_name = stu.getAttribute('name') # 獲取標簽中內容 id = stu.getElementsByTagName('id')[0].childNodes[0].nodeValue name = stu.getElementsByTagName('name')[0].childNodes[0].nodeValue age = stu.getElementsByTagName('age')[0].childNodes[0].nodeValue gender = stu.getElementsByTagName('gender')[0].childNodes[0].nodeValue print('st_id:', st_id, ', st_name:',st_name) print('id:', id, ', name:', name, ', age:', age, ', gender:',gender)
- 輸出結果:
-
st_id: stu1 , st_name: stu id: 1001 , name: 張三 , age: 22 , gender: 男 st_id: stu2 , st_name: stu id: 1002 , name: 李四 , age: 21 , gender: 女
- 通過輸出結果,我們可以發現已經獲取了標簽屬性值和標簽內容了。
-
SAX 方式解析
使用 SAX 解析 XML 文檔主要涉及到解析器和事件處理器,解析器負責讀取 XML 文檔,並向事件處理器發送事件,事件處理器負責對事件作出響應,對傳遞的 XML 數據進行處理。
Python 使用 SAX 處理 XML 需要用到 xml.sax 中的 parse 函數和 xml.sax.handler 中的 ContentHandler 類,下面看一下 ContentHandler 類中的一些方法。
-
characters(content):調用時機:從行開始,遇到標簽之前,存在字符,content 的值為這些字符串;從一個標簽,遇到下一個標簽之前, 存在字符,content 的值為這些字符串;從一個標簽,遇到行結束符之前,存在字符,content 的值為這些字符串。
-
startDocument():文檔啟動的時候調用。
-
endDocument():解析器到達文檔結尾時調用。
-
startElement(name, attrs):遇到 XML 開始標簽時調用,name 是標簽的名字,attrs 是標簽的屬性值字典。
-
endElement(name):遇到 XML 結束標簽時調用。
下面通過示例看一下如何通過 SAX 方式解析 XML。
-
-
import xml.sax class StudentHandler(xml.sax.ContentHandler): def __init__(self): self.id = "" self.name = "" self.age = "" self.gender = "" # 元素開始調用 def startElement(self, tag, attributes): self.CurrentData = tag if tag == "student": stu_name = attributes["name"] print("stu_name:", stu_name) # 元素結束調用 def endElement(self, tag): if self.CurrentData == "id": print("id:", self.id) elif self.CurrentData == "name": print("name:", self.name) elif self.CurrentData == "age": print("age:", self.age) elif self.CurrentData == "gender": print("gender:", self.gender) self.CurrentData = "" # 讀取字符時調用 def characters(self, content): if self.CurrentData == "id": self.id = content elif self.CurrentData == "name": self.name = content elif self.CurrentData == "age": self.age = content elif self.CurrentData == "gender": self.gender = content if (__name__ == "__main__"): # 創建 XMLReader parser = xml.sax.make_parser() # 關閉命名空間 parser.setFeature(xml.sax.handler.feature_namespaces, 0) # 重寫 ContextHandler Handler = StudentHandler() parser.setContentHandler(Handler) parser.parse("test.xml")
- 輸出結果:
-
stu_name: stu id: 1001 name: 張三 age: 22 gender: 男 stu_name: stu id: 1002 name: 李四 age: 21 gender: 女
-
ElementTree 方式解析
Python 提供了兩種 ElementTree 的實現方式。一個是純 Python 實現的 xml.etree.ElementTree,另一個是 C 語言實現 xml.etree.cElementTree,使用 C 語言實現的方式速度更快且內存消耗更少。Python3.3 之后,ElemenTree 模塊會自動優先使用 C 加速器,如果不存在 C 實現,則會使用 Python 實現。因此,使用 Python3.3+ 時,只需要 import xml.etree.ElementTree 即可。下面看一下示例。
-
import xml.etree.ElementTree as ET tree = ET.parse("test.xml") # 根節點 root = tree.getroot() # 標簽名 print('root_tag:',root.tag) for stu in root: # 屬性值 print ("stu_name:", stu.attrib["name"]) # 標簽中內容 print ("id:", stu[0].text) print ("name:", stu[1].text) print("age:", stu[2].text) print("gender:", stu[3].text)
- 輸出結果:
-
root_tag: list stu_name: stu id: 1001 name: 張三 age: 22 gender: 男 stu_name: stu id: 1002 name: 李四 age: 21 gender: 女