直接上代码
python 中xml库 ElementTree的使用
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @File : xml.py
# @Author: shadow
# @Date : 2020/10/30
# @Desc : xml
import time, os
import xml.etree.ElementTree as ET
# 处理XML缩进和换行
def pretty_xml(element, indent='\t', newline='\n', level=0): # elemnt为传进来的Elment类,参数indent用于缩进,newline用于换行
if element: # 判断element是否有子元素
if (element.text is None) or element.text.isspace(): # 如果element的text没有内容
element.text = newline + indent * (level + 1)
else:
element.text = newline + indent * (level + 1) + element.text.strip() + newline + indent * (level + 1)
# else: # 此处两行如果把注释去掉,Element的text也会另起一行
# element.text = newline + indent * (level + 1) + element.text.strip() + newline + indent * level
temp = list(element) # 将element转成list
for subelement in temp:
if temp.index(subelement) < (len(temp) - 1): # 如果不是list的最后一个元素,说明下一个行是同级别元素的起始,缩进应一致
subelement.tail = newline + indent * (level + 1)
else: # 如果是list的最后一个元素, 说明下一行是母元素的结束,缩进应该少一个
subelement.tail = newline + indent * level
pretty_xml(subelement, indent, newline, level=level + 1) # 对子元素进行递归操作
class Param:
def __init__(self, param_file, root_node=""):
self.file = param_file
if os.path.exists(param_file):
self.tree = ET.parse(param_file)
self.root = self.tree.getroot()
else: # 新建xml文件
if not root_node:
print("No root_node")
raise NameError
self.root = ET.Element(root_node)
self.tree = ET.ElementTree(self.root)
# 修改节点
def set_note(self, param, node):
if param.get('text'): node.text = param['text']
if param.get('attrib'): node.attrib = param['attrib']
# 添节点
def add_note(self, param, parent):
'''
param: 节点信息字典,(key:节点名,value:节点内容包括text和attrib)
parent: 添加位置(父节点)
'''
for name, value in param.items():
node = parent.find(name)
if isinstance(node, ET.Element): # 注意:使用 if node判断不能得到是否有节点 ???, 可以使用findall + for
self.set_note(value, node)
else:
node = ET.Element(name)
if value.get('text'): node.text = value['text']
if value.get('attrib'): node.attrib = value['attrib']
parent.append(node)
self.update()
# 删除节点,可以匹配属性参数
def del_node(self, name, parent, param={}):
'''
name: 节点名
parent: 添加位置(父节点)
param: key:属性名,value:属性值
'''
nodes = parent.findall(name)
for node in nodes:
if param:
for k, v in param.items():
if node.get(k) != v: # 给的属性参数有不匹配,不删除
break
else:
parent.remove(node)
else:
parent.remove(node)
self.update()
# 查找节点
def find_node(self, name):
nodes = self.root.iter(name)
return self.get_note(nodes)
# 获取节点信息,转成字典
def get_note(self, start=''):
'''
tag: 保存数据字典
start: 起始节点(默认根节点)
'''
tag = {}
if not start:
start = self.root
# print(start)
for node in start:
if list(node): # 有子节点
# print(node, node.tag, tag)
tag[node.tag] = self.get_note(node) # 递归执行
else:
tag[node.tag] = {}
if node.text:
tag[node.tag]['text'] = node.text
if node.attrib:
tag[node.tag]['attrib'] = node.attrib
return tag
# 更新xml
def update(self):
# save_path = 'camera_params_' + self.time.split()[0] + '.xml'
pretty_xml(self.root)
# print(list(self.root))
self.tree.write(self.file, 'UTF-8', xml_declaration=True)
if __name__ == '__main__':
param = Param('./camera_params1.xml', "shadow")
param.add_note({'shadow': {'attrib': {'age': '30', 'sex': 'male'}}}, param.root)
# param.add_note({'about': {'attrib': {'author': 'shadow', 'email': 'yinlu@flyaudio.cn',
# 'date': time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}}}, param.root)
# param.del_node('shadow', param.root, {'age': 30, 'sex': 'male'})
# param.update()
tag = param.get_note()
print(tag)
print(param.find_node('eason'))
xml文件
<?xml version='1.0' encoding='UTF-8'?>
<student>
<test>
<test1>
<eason> shadow eason </eason>
</test1>
<test2> test2 </test2>
<test3> test3 </test3>
</test>
<shadow age="30" sex="male"> handsome boy </shadow>
</student>
执行结果
{'test': {'test1': {'eason': {'text': ' shadow eason '}}, 'test2': {'text': ' test2 '}, 'test3': {'text': ' test3 '}}, 'shadow': {'text': ' handsome boy ', 'attrib': {'age': '30', 'sex': 'male'}}}
{'eason': {'text': ' shadow eason '}}
代码中将节点信息转成了字典,方便后续使用
常用函数说明
- ET.ElementTree(xxx.xml):生成文档对象
- tag:标签名
- text:子节点的内容
- attrib:子节点的属性
- append(son):为当前节点添加个子节点
- get(aa):获取当前节点xx中属性aa(key)的值
- set(key,value):设置当前节点的属性值,最后再write写入文件
- keys():获取当前节点所有属性的keys,返回列表
- items():获取当前节点的所有属性值,每对属性都是键值对
- find(xxx):获取第一个寻找到的xxx子节点
- findtext(xxx):获取到第一个找到的子节点xxx的内容
- findall(xxx):获取所有的xxx节点
- iter(xxx):遍历获取指定节点xxx,并返回一个迭代器
- iterfind(xxx):遍历获取指定节点xxx,并返回一个迭代器
- itertext():获取当前节点中子孙节点的所有内容,并返回一个迭代器
- makeelement(xxx):创建一个新的节点xxx,仅为创建