在做目標檢測的時候,我們獲取到圖片的xml文件,我們想利用xml文件來解析得到我們想要的信息。或者我們想要對xml文件做一些修改,下面我將利用Python中自帶的xml包來完成這一系列的操作(其實還有一個用於解析HTML的包lxml也可以解析xml文件,也非常好用的,具體使用方法可以參看這篇博客)。參考網站我放在的底部,里面講得也很詳細。本文利用來演示的xml模板結構如下圖:
一、讀取並解析xml文件
我們主要使用的模塊是xml.etree.ElementTree
1、解析xml——獲取xml樹
import xml.etree.ElementTree as ET file_xml = '/home/g4/桌面/project/xxxx/99.xml' # xml文件路徑
tree = ET.parse(file_xml)
type(tree)
xml.etree.ElementTree.ElementTree
這里的tree的對象是ElementTree,從名字也可以知道這個數據結構類似於多叉樹,我們可以通過dir()來查看這個類的屬性和方法。
dir(tree)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_root', '_setroot', 'find', 'findall', 'findtext', 'getiterator', 'getroot', 'iter', 'iterfind', 'parse', 'write', 'write_c14n']
我們這里可以看到里面有find方法,findall方法,之后會講到,使用方式。
我們接下來要獲取其根節點,以及其他節點的內容。
2、解析xml——獲取子節點及其節點內容
獲得一棵樹之后我們,我們通過tree的getroot()方法來獲得整顆樹的根結點
root = tree.getroot() type(root)
xml.etree.ElementTree.Element
dir(root)
['__class__', '__copy__', '__deepcopy__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'attrib', 'clear', 'extend', 'find', 'findall', 'findtext', 'get', 'getchildren', 'getiterator', 'insert', 'items', 'iter', 'iterfind', 'itertext', 'keys', 'makeelement', 'remove', 'set', 'tag', 'tail', 'text']
我們可以看到根結點的數據類型是Element,其實這棵樹的所有節點數據類型都是Element,下面介紹這些方法和屬性
- root.find('xxx'):返回的是一個Element對象,也就是在該節點下提取出叫做‘xxx’這個字節點(如果有多個叫做xxx的子節點,將會返回首個)
- root.findall('xxx'):返回值是一個列表,列表的每個元素是Element,也就是返回該節點下叫做‘xxx’的所有子節點,用list來儲存
- root.attrib : 返回該Element所有的“屬性”,是一個字典,該節點的“屬性”就是<里面id,name這些東西>,一會可以結合示例xml文件,看到具體的返回值。
- root.text: 返回一個字符串,是這個根節點的所包含的內容(也就是<obj>xxxx<obj>中的xxxx)
接下來我們就根據着文章開頭的示例xml,來展示一下以上介紹到的方法和屬性
path = root.find('path') # 獲取root節點(annotation)下的叫做path的這個節點 type(path)
xml.etree.ElementTree.Element
root.attrib # 獲取annotation節點的屬性(包含有兩個屬性一個是name,一個是id)
{'name': 'Panama', 'id': '1234'}
path.text # 獲取path節點的內容
'百度'
root.findall('object')
[<Element 'object' at 0x7fd9adcec110>, <Element 'object' at 0x7fd9adcecbf0>]
可以看到第一行中我們獲取了root的字節點path,path也是一個Element的類別,因此它也是有上面提到的那些方法和屬性的。
我們可以看一下最后一行命令,返回的這個列表,里面儲存的元素顯示的是節點的內存地址。我們前面提到tree也是有findall方法的,其實如果使用tree的findall('object')得到的結果也是一樣的。
tree.findall('object')
[<Element 'object' at 0x7fd9adcec110>, <Element 'object' at 0x7fd9adcecbf0>]
我們可以看到內存地址也是一樣的,因此這兩種方式來搜索得到子節點是一模一樣的。
二、修改xml文件
我們已經可以提取xml中的信息了,接下來我們可以修改獲取到的xml文件里的信息。
1、修改節點內容
如果要修改節點的內容我們可以直接使用Element.text = 'xxxx',就就可以完成修改了。
path.text = '修改后' path = root.find('path') path.text
'修改后'
上面的例子顯示path節點的text已經從原來的‘百度’變成了‘修改后’,並且在重新從root中獲取path節點,也是顯示修改之后的結果。因此修改節點內容是非常方簡單的。
2、修改節點屬性
新增節點屬性。Element.set(新屬性名,新值)
root.set('sex', '男') root.attrib
{'name': 'Panama', 'id': '1234', 'sex': '男'}
修改節點的屬性,也是使用Element中的set方法。Element.set(待修改的屬性名,新值)
root.set('id', '4321') root.attrib
{'name': 'Panama', 'id': '4321', 'sex': '男'}
可以看到root的id這個屬性已經被修改成了4321。
(刪除屬性值,我還沒找到對應的方法。。。。)
3、刪除和增加子節點
如果要在一個Element下新一個子節點,我們采用Element.append(childElement)的方式。
path = root.find('path') path.findall('object')
[]
obj = root.find('object') path.append(obj) path.findall('object')
[<Element 'object' at 0x7fd9adcec110>]
可以看到在path下本來是沒有object這個子節點的,但是在append之后就有了(要注意的是我們append只有是Element對象)
刪除一個子節點采用的是Element.remove(childElement)的方式。
path.remove(obj) path.findall('object')
[]
也要注意的是參數只能是Element對象並且還得是同一個內存。
obj = root.findall('object')[1] path.remove(obj)
ValueError: list.remove(x): x not in list
如果我們刪除的是另一個obj對象(這里會報錯的),原因是path的子節點的並不是我們新創建的這個obj。
三、保存xml文件
對於我們已經修改完成的xml,以上改了屬性,增加了子節點,刪除了字節點,把操作后的tree保存成新的xml文件。采用
import xml.etree.ElementTree as ET file_xml = '/home/g4/桌面/project/安全帽100/99.xml' tree = ET.parse(file_xml) # 讀取tree
root = tree.getroot() path = root.find('path') obj = root.find('object') path.append(obj) # 在path子節點下增加一個子節點
root.remove(obj) # 在root節點下刪除一個子節點
new_tree = ET.ElementTree(root) # root為修改后的root
new_tree.write("test.xml", encoding='utf-8') # 保存為xml文件
最主要的保存操作是最后兩行,這里由於存在中文,因此傳入參數encoding=‘utf-8’。
看看最后結果。
參考鏈接:
https://blog.csdn.net/weixin_42782150/article/details/106219001