帶分隔符的文件僅有兩維的數據:行 & 列。如果我們想在程序之間交換數據結構,需要一種方法把層次結構,序列,集合和其它的數據結構編碼成文本。
今天要說的 XML 是最突出的處理上述這種轉換的標記格式,它使用標籤(tag)分隔數據。XML 在軟體領域的用途非常廣泛。
XML 是什麼?如果非要對其做一個定義式的說明,那這裡我不得不引用一下 w3school 裡面簡潔而明快的說明:
XML 指可擴展標記語言(EXtensible Markup Language); XML 是一種標記語言,類似於 HTML; XML 的設計宗旨是傳輸數據,而非顯示數據; XML 標籤沒有被預定義,需要自行定義標籤; XML 被設計為具有自我描述性; XML 是 W3C 的推薦標準。
XML 指可擴展標記語言(EXtensible Markup Language);
XML 的設計宗旨是傳輸數據,而非顯示數據;
如果你想要詳細瞭解和學習 XML 的話,可以去閱讀 w3school 的 XML 教程即可,裡面講述的很詳細,在下面我還會引用一些裡面的內容。
XML 的重要性在於它是用來傳輸數據的,因此,特別是在 Web 編程中我們經常會用到它。有了它,讓數據傳輸變的更加簡單,這麼重要的東西,我大 Python 當然支持。
有大佬曾經說過:「一個引人關注的東西總會有很多人從不同側面去研究它」。這個在編程中也同樣適用,所以對於 XML 這個紅得發紫的東西,Python 提供了多種模塊來處理。
當然還有一些別的,比如 xml.parse.expat,xml.etree.ElementTree 等等,我就不在列舉了,碰到的時候再去查查,否則光看這些東西頭就大了,而且無聊的很。
先要做一個 XML 文檔,我自己想也想不出個啥太好的來,所以直接用 w3school 中的一個例子,如下圖所示:
上圖表示下面的 XML 中的一本書:
<bookstore> <book category="COOKING"> <title lang="en">Everyday Italian</title> <author>Giada De Laurentiis</author> <year>2005</year> <price>30.00</price> </book> <book category="CHILDREN"> <title lang="en">Harry Potter</title> <author>J K. Rowling</author> <year>2005</year> <price>29.99</price> </book> <book category="WEB"> <title lang="en">Learning XML</title> <author>Erik T. Ray</author> <year>2003</year> <price>39.95</price> </book> </bookstore>
將上述的 XML 保存並且命名為 test.xml 文件,接下來就是以它為對象,練習各種操作了。
>>> import xml.etree.ElementTree as ET >>> tree = ET.ElementTree(file = test.xml) >>> tree <xml.etree.ElementTree.ElementTree object at 0x00000000025B8630>
上面建立起 XML 解析樹對象,然後通過根節點向下開始讀取各個元素(element 對象)。
在上述 XML 文檔中,根元素是 bookstore,它沒有屬性,也可以說是屬性為空。
>>> root = tree.getroot() >>> root.tag bookstore >>> root.attrib {}
要想將根下面的元素都讀取出來,可以進行如下操作:
>>> for child in root: ... print(child.tag,child.attrib) ... (book, {category: COOKING}) (book, {category: CHILDREN}) (book, {category: WEB})
也可以像下面這樣讀取指定元素的信息:
>>> root[0].tag book >>> root[0].attrib {category: COOKING} >>> root[0].text
上述的 root[0].text 無內容,再深入一層,我們就可以看到內容了:
>>> root[0][0].tag title >>> root[0][0].attrib {lang: en} >>> root[0][0].text Everyday Italian
對於 ElementTree 對象,有一個 iter() 方法可以對指定名稱的子節點進行深度優先遍歷,例如下面這樣:
>>> for ele in tree.iter(tag=book): ... print(ele.tag,ele.attrib) ... (book, {category: COOKING}) (book, {category: CHILDREN}) (book, {category: WEB})
上述代碼是遍歷名稱為 book 的節點,如果不指定節點的話,就是將所有的元素遍歷一遍:
>>> for ele in tree.iter(): ... print(ele.tag,ele.attrib) ... (bookstore, {}) (book, {category: COOKING}) (title, {lang: en}) (author, {}) (year, {}) (price, {}) (book, {category: CHILDREN}) (title, {lang: en}) (author, {}) (year, {}) (price, {}) (book, {category: WEB}) (title, {lang: en}) (author, {}) (year, {}) (price, {})
除了上面的方法外,還可以通過路徑搜索到指定的元素,然後讀取其內容,這就是 xpath,關於 xpath 是什麼,在這不多做介紹,感興趣的可以去 Google。
我們還是用上面的例子,為了方便查看,我把內容再粘貼過來,下面的內容記得保存並且命名為 test.xml。
上一篇文章我們主要是對 xml 進行了讀取的有關操作,其實還可以對 XML 進行編輯,也就是增刪改查的功能,下面我們來操作一下:
>>> import xml.etree.ElementTree as ET >>> tree = ET.ElementTree(file = "test.xml") >>> root = tree.getroot() #獲得根 >>> root[1].tag book >>> del root[1] >>> for ele in root: ... print(ele.tag) ... book book
如上,我們成功的刪除了一個節點,原來有 3 個 book 節點,現在就只剩下兩個了。接下來讓我們打開源文件看看,是不是正好缺少了第 2 個節點呢?結果讓我們很失望,源文件並沒有什麼變化。
確實如此,源文件並沒有變,因為到了這一步的修改動作還只是停留在內存裏,還沒有將修改的結果輸出到文件,不要忘記我們是在內存中建立的 ElementTree 對象。那麼該如何做呢?請接著往下看:
>>> import os >>> outpath = os.getcwd() >>> file = outpath + "/test.xml"
把當前文件的路徑拼裝好。
>>> tree.write(file)
做完上面的操作以後再去看源文件,已經變成兩個節點了。
除了刪除,也是可以修改的:
>>> for price in root.iter(price): #原來每本書的價格 ... print(price.text) ... 30.00 39.95 >>> for price in root.iter(price): #每本上漲 10 元並做標記 ... new_price = float(price.text) + 10 ... price.text = str(new_price) ... price.set("updated","up") ... >>> tree.write(file)
然後我們來查看一下源文件:
<bookstore> <book category="COOKING"> <title lang="en">Everyday Italian</title> <author>Giada De Laurentiis</author> <year>2005</year> <price updated="up">50.0</price> </book> <book category="WEB"> <title lang="en">Learning XML</title> <author>Erik T. Ray</author> <year>2003</year> <price updated="up">49.95</price> </book> </bookstore>
通過對比我們可以發現,不僅價格改變了,而且在 price 標籤裡面增加了屬性標記。
上面我們是用 del 來刪除某個元素,其實這個在編程中我們用的並不多,一般情況下更喜歡用 remove() 方法。比如要刪除 price = 50 的書,可以像下面這樣操作:
>>> tree.write(file) >>> for book in root.findall("book"): ... price = book.find("price").text ... if float(price) == 50: ... root.remove(book) ... >>> tree.write(file)
於是就有了下面的結果:
<bookstore> <book category="WEB"> <title lang="en">Learning XML</title> <author>Erik T. Ray</author> <year>2003</year> <price updated="up">49.95</price> </book> </bookstore>
接下來我們來看看增加元素:
>>> import xml.etree.ElementTree as ET >>> tree = ET.ElementTree(file = test.xml) >>> root = tree.getroot() >>> ET.SubElement(root,"book") # 在root裡面添加book節點 <Element book at 0x000000000209C778> >>> for ele in root: ... print(ele.tag) ... book book >>> b2 = root[1] >>> b2.text = python >>> tree.write(test.xml)
這樣就大功告成了,然後再像上面一樣看一下源文件,發現果真增加了。
ET 裡面的屬性 & 方法很多,這裡列出常用的幾個,供使用中備查。
1.Element 對象
常用的屬性如下:
針對屬性的操作如下:
針對後代的操作如下:
2.ElementTree 對象
更多內容,歡迎關注公眾號「Python空間」,期待和你的交流。