Python 操作XML文件一文通
點(diǎn)擊上方“菜鳥(niǎo)學(xué)Python”,選擇“星標(biāo)”公眾號(hào)
超級(jí)無(wú)敵干貨,第一時(shí)間送達(dá)?。?!
大家好,我是菜鳥(niǎo)哥。
我們經(jīng)常需要解析用不同語(yǔ)言編寫(xiě)的數(shù)據(jù),Python 提供了許多第三方庫(kù)來(lái)解析或拆分用其他語(yǔ)言編寫(xiě)的數(shù)據(jù),今天我們來(lái)學(xué)習(xí)下 Python XML 解析器的相關(guān)功能。

下面一起來(lái)看看吧~
什么是 XML?
XML 是可擴(kuò)展標(biāo)記語(yǔ)言,它在外觀上類似于 HTML,但 XML 用于數(shù)據(jù)表示,而 HTML 用于定義正在使用的數(shù)據(jù)。XML 專門(mén)設(shè)計(jì)用于在客戶端和服務(wù)器之間來(lái)回發(fā)送和接收數(shù)據(jù)。看看下面的例子:
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<food>
<item name="breakfast">Idly</item>
<price>$2.5</price>
<description>
Two idly's with chutney
</description>
<calories>553</calories>
</food>
<food>
<item name="breakfast">Paper Dosa</item>
<price>$2.7</price>
<description>
Plain paper dosa with chutney
</description>
<calories>700</calories>
</food>
<food>
<item name="breakfast">Upma</item>
<price>$3.65</price>
<description>
Rava upma with bajji
</description>
<calories>600</calories>
</food>
<food>
<item name="breakfast">Bisi Bele Bath</item>
<price>$4.50</price>
<description>
Bisi Bele Bath with sev
</description>
<calories>400</calories>
</food>
<food>
<item name="breakfast">Kesari Bath</item>
<price>$1.95</price>
<description>
Sweet rava with saffron
</description>
<calories>950</calories>
</food>
</metadata>
上面的示例顯示了命名為“Sample.xml”的文件的內(nèi)容,后面的代碼示例都會(huì)基于此 XML 例子來(lái)進(jìn)行。
Python XML 解析模塊
Python 允許使用兩個(gè)模塊解析這些 XML 文檔,即 xml.etree.ElementTree 模塊和 Minidom(最小 DOM 實(shí)現(xiàn))。解析意味著從文件中讀取信息,并通過(guò)識(shí)別特定 XML 文件的各個(gè)部分將其拆分為多個(gè)片段。讓我們進(jìn)一步了解如何使用這些模塊來(lái)解析 XML 數(shù)據(jù)。
xml.etree.ElementTree 模塊:
該模塊幫助我們將 XML 數(shù)據(jù)格式化為樹(shù)結(jié)構(gòu),這是分層數(shù)據(jù)的最自然表示。元素類型允許在內(nèi)存中存儲(chǔ)分層數(shù)據(jù)結(jié)構(gòu),并具有以下屬性:
| Property | Description |
|---|---|
| Tag | 一個(gè)字符串,表示正在存儲(chǔ)的數(shù)據(jù)類型 |
| Attributes | 由存儲(chǔ)為字典的許多屬性組成 |
| Text String | 包含需要顯示的信息的文本字符串 |
| Tail String | 如有必要,也可以有尾弦 |
| Child Elements | 由許多存儲(chǔ)為序列的子元素組成 |
ElementTree 是一個(gè)封裝元素結(jié)構(gòu)并允許與 XML 相互轉(zhuǎn)換的類,現(xiàn)在讓我們嘗試使用 python 模塊解析上述 XML 文件。
有兩種方法可以使用ElementTree模塊解析文件。
第一個(gè)是使用 parse() 函數(shù),第二個(gè)是 fromstring() 函數(shù)。 parse() 函數(shù)解析作為文件提供的 XML 文檔,而 fromstring 在作為字符串提供時(shí)解析 XML,即在三引號(hào)內(nèi)。
使用 parse() 函數(shù):
如前所述,該函數(shù)采用文件格式的 XML 進(jìn)行解析,看看下面的例子:
import xml.etree.ElementTree as ET
mytree = ET.parse('sample.xml')
myroot = mytree.getroot()
我們需要做的第一件事是導(dǎo)入 xml.etree.ElementTree 模塊,然后使用 parse() 方法解析“Sample.xml”文件,getroot() 方法返回“Sample.xml”的根元素。
當(dāng)執(zhí)行上述代碼時(shí),我們不會(huì)看到返回的輸出,但只要不會(huì)有錯(cuò)誤就表明代碼已成功執(zhí)行。要檢查根元素,可以簡(jiǎn)單地使用 print 語(yǔ)句,如下所示:
import xml.etree.ElementTree as ET
mytree = ET.parse('sample.xml')
myroot = mytree.getroot()
print(myroot)
Output:
<Element ‘metadata’ at 0x033589F0>
上面的輸出表明我們的 XML 文檔中的根元素是“元數(shù)據(jù)”。
使用 fromstring() 函數(shù)
我們還可以使用 fromstring() 函數(shù)來(lái)解析字符串?dāng)?shù)據(jù),我們需要將 XML 作為三引號(hào)內(nèi)的字符串傳遞,如下所示:
import xml.etree.ElementTree as ET
data='''<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<food>
<item name="breakfast">Idly</item>
<price>$2.5</price>
<description>
Two idly's with chutney
</description>
<calories>553</calories>
</food>
</metadata>
'''
myroot = ET.fromstring(data)
#print(myroot)
print(myroot.tag)
上面的代碼將返回與前一個(gè)相同的輸出,用作字符串的 XML 文檔只是“Sample.xml”的一部分,已將其用于提高可見(jiàn)性,也可以使用完整的 XML 文檔。
還可以使用“標(biāo)簽”對(duì)象檢索根標(biāo)簽,如下所示:
print(myroot.tag)
Output:
metadata
還可以通過(guò)僅指定要在輸出中看到的字符串部分來(lái)對(duì)標(biāo)記字符串輸出進(jìn)行切片。
print(myroot.tag[0:4])
Output:
meta
如前所述,標(biāo)簽也可以具有字典屬性。要檢查根標(biāo)簽是否有任何屬性,您可以使用“attrib”對(duì)象,如下所示:
print(myroot.attrib)
Output:
{}
可以看到,輸出是一個(gè)空字典,因?yàn)槲覀兊母鶚?biāo)簽沒(méi)有屬性。
尋找感興趣的元素
根也由子標(biāo)簽組成,要檢索根標(biāo)簽的子標(biāo)簽,可以使用以下命令:
print(myroot[0].tag)
Output:
food
現(xiàn)在,如果要檢索根的所有第一個(gè)子標(biāo)記,可以使用 for 循環(huán)對(duì)其進(jìn)行迭代,如下所示:
for x in myroot[0]:
print(x.tag, x.attrib)
Output:
item {‘name’: ‘breakfast’}
price {}
description {}
calories {}
返回的所有項(xiàng)目都是食物的子屬性和標(biāo)簽。
要使用 ElementTree 從 XML 中分離出文本,可以使用 text 屬性。例如,如果想檢索關(guān)于第一個(gè)食物的所有信息,應(yīng)該使用以下代碼:
for x in myroot[0]:
print(x.text)
Output:
Idly
$2.5
Two idly’s with chutney
553
可以看出,第一項(xiàng)的文本信息已作為輸出返回?,F(xiàn)在如果想以特定價(jià)格顯示所有商品,可以使用 get() 方法,此方法訪問(wèn)元素的屬性。
for x in myroot.findall('food'):
item =x.find('item').text
price = x.find('price').text
print(item, price)
Output:
Idly $2.5
Paper Dosa $2.7
Upma $3.65
Bisi Bele Bath $4.50
Kesari Bath $1.95
上面的輸出顯示了所有必需的項(xiàng)目以及每個(gè)項(xiàng)目的價(jià)格,使用 ElementTree,還可以修改 XML 文件。
修改 XML 文件
我們的 XML 文件中的元素是可以被操縱的,為此,可以使用 set() 函數(shù)。讓我們先來(lái)看看如何在 XML 中添加一些東西。
添加到 XML:
以下示例顯示了如何在項(xiàng)目描述中添加內(nèi)容。
for description in myroot.iter('description'):
new_desc = str(description.text)+'wil be served'
description.text = str(new_desc)
description.set('updated', 'yes')
mytree.write('new.xml')
write() 函數(shù)有助于創(chuàng)建一個(gè)新的 xml 文件并將更新的輸出寫(xiě)入該文件,但是也可以使用相同的功能修改原始文件。執(zhí)行上述代碼后,將能夠看到已創(chuàng)建一個(gè)包含更新結(jié)果的新文件。
上圖顯示了我們食品項(xiàng)目的修改描述。要添加新的子標(biāo)簽,可以使用 SubElement() 方法。例如,如果想在第一項(xiàng) Idly 中添加新的專業(yè)標(biāo)簽,可以執(zhí)行以下操作:
ET.SubElement(myroot[0], 'speciality')
for x in myroot.iter('speciality'):
new_desc = 'South Indian Special'
x.text = str(new_desc)
mytree.write('output5.xml')
Output:
就像我們所見(jiàn)到的,在第一個(gè)食物標(biāo)簽下添加了一個(gè)新標(biāo)簽??梢酝ㄟ^(guò)在 [] 括號(hào)內(nèi)指定下標(biāo)來(lái)在任意位置添加標(biāo)簽。
下面讓我們看看如何使用這個(gè)模塊刪除項(xiàng)目。
從 XML 中刪除:
要使用 ElementTree 刪除屬性或子元素,可以使用 pop() 方法,此方法將刪除用戶不需要的所需屬性或元素。
myroot[0][0].attrib.pop('name', None)
# create a new XML file with the results
mytree.write('output5.xml')
Output:

上圖顯示 name 屬性已從 item 標(biāo)記中刪除。要?jiǎng)h除完整的標(biāo)簽,可以使用相同的 pop() 方法,如下所示:
myroot[0].remove(myroot[0][0])
mytree.write('output6.xml')
Output:

輸出顯示食品標(biāo)簽的第一個(gè)子元素已被刪除。如果要?jiǎng)h除所有標(biāo)簽,可以使用 clear() 函數(shù),如下所示:
myroot[0].clear()
mytree.write('output7.xml')
執(zhí)行上述代碼時(shí),food 標(biāo)簽的第一個(gè)子標(biāo)簽將被完全刪除,包括所有子標(biāo)簽。
到目前為止,我們一直在使用 Python XML 解析器中的 xml.etree.ElementTree 模塊?,F(xiàn)在讓我們看看如何使用 Minidom 解析 XML。
xml.dom.minidom Module
該模塊基本上是由精通DOM(文檔對(duì)象模塊)的人使用的,DOM 應(yīng)用程序通常首先將 XML 解析為 DOM。在 xml.dom.minidom 中,可以通過(guò)以下方式實(shí)現(xiàn)
使用 parse() 函數(shù):
第一種方法是通過(guò)提供要解析的 XML 文件作為參數(shù)來(lái)使用 parse()函數(shù)。例如:
from xml.dom import minidom
p1 = minidom.parse("sample.xml")
執(zhí)行此操作后,將能夠拆分 XML 文件并獲取所需的數(shù)據(jù)。還可以使用此函數(shù)解析打開(kāi)的文件。
dat=open('sample.xml')
p2=minidom.parse(dat)
在這種情況下,存儲(chǔ)打開(kāi)文件的變量作為參數(shù)提供給 parse 函數(shù)。
使用 parseString() 方法:
當(dāng)我們想要提供要作為字符串解析的 XML 時(shí)使用此方法。
p3 = minidom.parseString('<myxml>Using<empty/> parseString</myxml>')
可以使用上述任何方法解析 XML,現(xiàn)在讓我們嘗試使用這個(gè)模塊獲取數(shù)據(jù)
尋找感興趣的元素
在我的文件被解析后,如果我們嘗試打印它,返回的輸出會(huì)顯示一條消息,即存儲(chǔ)解析數(shù)據(jù)的變量是 DOM 的對(duì)象。
dat=minidom.parse('sample.xml')
print(dat)
Output:
<xml.dom.minidom.Document object at 0x03B5A308>
使用 GetElementsByTagName 訪問(wèn)元素
tagname= dat.getElementsByTagName('item')[0]
print(tagname)
如果我們嘗試使用 GetElementByTagName 方法獲取第一個(gè)元素,我將看到以下輸出:
<DOM Element: item at 0xc6bd00>
請(qǐng)注意,只返回了一個(gè)輸出,因?yàn)闉榉奖闫鹨?jiàn),這里使用了 [0] 下標(biāo),這將在進(jìn)一步的示例中被刪除。
要訪問(wèn)屬性的值,我們將不得不使用 value 屬性,如下所示:
dat = minidom.parse('sample.xml')
tagname= dat.getElementsByTagName('item')
print(tagname[0].attributes['name'].value)
Output:
breakfast
要檢索這些標(biāo)簽中存在的數(shù)據(jù),可以使用 data 屬性,如下所示:
print(tagname[1].firstChild.data)
Output:
Paper Dosa
還可以使用 value 屬性拆分和檢索屬性的值。
print(items[1].attributes['name'].value)
Output:
breakfast
要打印出我們菜單中的所有可用項(xiàng)目,可以遍歷這些項(xiàng)目并返回所有項(xiàng)目。
for x in items:
print(x.firstChild.data)
Output:
Idly
Paper Dosa
Upma
Bisi Bele Bath
Kesari Bath
要計(jì)算我們菜單上的項(xiàng)目數(shù),可以使用 len() 函數(shù),如下所示:
print(len(items))
Output:
5
輸出指定我們的菜單包含 5 個(gè)項(xiàng)目。
推薦閱讀:
入門(mén): 最全的零基礎(chǔ)學(xué)Python的問(wèn)題 | 零基礎(chǔ)學(xué)了8個(gè)月的Python | 實(shí)戰(zhàn)項(xiàng)目 |學(xué)Python就是這條捷徑
干貨:爬取豆瓣短評(píng),電影《后來(lái)的我們》 | 38年NBA最佳球員分析 | 從萬(wàn)眾期待到口碑撲街!唐探3令人失望 | 笑看新倚天屠龍記 | 燈謎答題王 |用Python做個(gè)海量小姐姐素描圖 |碟中諜這么火,我用機(jī)器學(xué)習(xí)做個(gè)迷你推薦系統(tǒng)電影
趣味:彈球游戲 | 九宮格 | 漂亮的花 | 兩百行Python《天天酷跑》游戲!
AI: 會(huì)做詩(shī)的機(jī)器人 | 給圖片上色 | 預(yù)測(cè)收入 | 碟中諜這么火,我用機(jī)器學(xué)習(xí)做個(gè)迷你推薦系統(tǒng)電影
小工具: Pdf轉(zhuǎn)Word,輕松搞定表格和水印! | 一鍵把html網(wǎng)頁(yè)保存為pdf!| 再見(jiàn)PDF提取收費(fèi)! | 用90行代碼打造最強(qiáng)PDF轉(zhuǎn)換器,word、PPT、excel、markdown、html一鍵轉(zhuǎn)換 | 制作一款釘釘?shù)蛢r(jià)機(jī)票提示器! |60行代碼做了一個(gè)語(yǔ)音壁紙切換器天天看小姐姐!|
年度爆款文案
點(diǎn)閱讀原文,看B站我的視頻!

