python xml(ElementTree)
python xml处理(ElementTree)
1. 模块导入
from xml.etree.ElementTree import ElementTree,Element,SubElement
2. 对象概述
- ElementTree:表示整个xml层级结构
- Element:表示树形结构中的父节点
- SubElement:表示树形结构中的所有子节点,有些节点既可以是父节点,也可以是子节点
3. ElementTree
3.1. API
getroot(self)
用途:返回xml树的根节点;
返回值:Element;
parse(self, source, parser=None)
用途:解析xml文件;
参数:source为xml文件名或文件对象,parser为xml解析器,默认为XMLParser;
返回值:返回xml树的根节点,Element;
find(self, path, namespaces=None)
用途:根据tag name或path查找首个匹配的Element对象,同getroot().find(path);
参数:path为包含tag或path的字符串,namespaces为命名空间前缀到全名的可选映射;
返回值:返回首个匹配的Element对象,查找失败则返回None;
findall(self, path, namespaces=None)
用途:根据tag name或path查找全部匹配的Element对象,同getroot().findall(path);
参数:path为包含tag或path的字符串,namespaces为命名空间前缀到全名的可选映射;
返回值:返回list,按xml文档顺序,包含所有匹配的Element对象;
findtext(self, path, default=None, namespaces=None)
用途:根据tag name或path查找首个匹配的Element对象的text值,同getroot().findtext(path);
参数:path为包含tag或path的字符串,namespaces为命名空间前缀到全名的可选映射;
返回值:返回首个匹配的Element对象的text值,查找失败则返回None;
write(self, file_or_filename, encoding=None, xml_declaration=None, default_namespace=None, method=None, *, short_empty_elements=True)
用途:将element树写入为xml文件
参数:
- file_or_filename为文件名或已打开的文件对象;
- encoding为编码方式,默认为US-ASCII;
- xml_declaration bool值,指示输出文件时是否需要添加xml文件头部声明,为None时,则如果编码不是US-ASCII、UTF-8或Unicode中的任何一种,则会添加XML声明;
- default_namespace,设置默认xml命名空间;
- method为xml、html、text或c14n,默认为xml;
- short_empty_elements,控制不包含内容的元素的格式。
4. Element
xml示例:
<field name="ack" type="uint16_t">响应码</field>
Element中类对象的值
- tag:对应xml文件Tag部分,以字符串结构存储,如上示例的'filed';
- attrib:对应xml文件Attribute部分,以字典结构存储,如上示例的'name="ack"';
- text:对应xml文件Element部分,以字符串结构存储,xml数据标签包裹的内容,如上示例的'响应码';
4.1. API
append(self, subelement, /)
用途:添加子对象;
参数:subelement为子对象;
clear(self, /)
用途:清空元素的后代、属性、text和tail也设置为None;
extend(self, elements, /)
用途:增加一串元素对象作为子元素
参数:elements为子对象;
find(self, /, path, namespaces=None)
用途:根据tag name或path查找首个匹配的Element对象;
findall(self, /, path, namespaces=None)
用途:根据tag name或path查找全部匹配的Element对象;
返回值:返回list;
findtext(self, /, path, default=None, namespaces=None)
用途:根据tag name或path查找全部匹配的Element对象的text值;
get(self, /, key, default=None)
用途:获取key对应的属性值,如该属性不存在则返回default值;
set(self, key, value, /)
用途:设置新的属性键与值;
insert(self, index, subelement, /)
用途:在指定位置插入子对象;
参数:subelement为子对象;
items(self, /)
用途:根据属性字典返回一个列表,列表元素为(key, value);
keys(self, /)
用途:返回包含所有元素属性键的列表;
remove(self, subelement, /)
用途:删除子对象;
参数:subelement为子对象;
5. 使用示例
以下代码示例均使用如下xml文件:
<?xml version='1.0' encoding='utf-8'?>
<messages>
<message name="SetDebugParam" id="100">
<description>调试配置</description>
<field name="opc" type="uint8_t">操作码</field>
<field name="parameter1" type="uint32_t">参数1</field>
<field name="parameter2" type="uint32_t">参数2</field>
<field name="parameter3" type="uint32_t">参数3</field>
</message>
</messages>
5.1. 文件解析
#!/usr/bin/env python
from xml.etree.ElementTree import ElementTree,Element,SubElement
# 解析field
def parse_field(message):
field_info = []
for item in message:
field_node = {}
if item.tag == "field":
field_node["name"] = item.attrib["name"]
field_node["type"] = item.attrib["type"]
field_node["text"] = item.text
field_info.append(field_node)
return field_info
# 解析文件
def parse_msg(xml_name):
node_table = {}
# 读取并解析xml文件
tree = ElementTree()
tree.parse(xml_name)
# 查找某个路径匹配的所有节点
msg_blocks = tree.findall("message")
for msg in msg_blocks:
# 获取name对应的值
node_table["name"] = msg.get("name")
# 获取id对应的值
node_table["id"] = msg.get("id")
# 解析fields
node_table["fields"] = parse_field(msg)
return node_table
node_table = parse_msg("./test.xml")
# 打印
print(node_table)
输出结果:
{'name': 'SetDebugParam', 'id': '100', 'fields': [{'name': 'opc', 'type': 'uint8_t', 'text': '操作码'}, {'name': 'parameter1', 'type': 'uint32_t', 'text': '参数1'}, {'name': 'parameter2', 'type': 'uint32_t', 'text': '参数2'}, {'name': 'parameter3', 'type': 'uint32_t', 'text': '参数3'}]}
5.2. 创建文件
#!/usr/bin/env python
from xml.etree.ElementTree import ElementTree,Element,SubElement
# 新建一个节点
def create_node(tag, property_map, text):
element = Element(tag, property_map)
element.text = text
return element
def make_xml(output_xml):
root = Element("messages")
# 新建节点
message_node = create_node("message", {"name": "SetDebugParam", "id": "100"}, "")
root.append(message_node)
description_node = create_node("description", {}, u'调试配置')
message_node.append(description_node)
field_opc = create_node("field", {"name": "opc", "type": "uint8_t"}, u'操作码')
field_p1 = create_node("field", {"name": "parameter1", "type": "uint32_t"}, u'参数1')
field_p2 = create_node("field", {"name": "parameter2", "type": "uint32_t"}, u'参数2')
field_p3 = create_node("field", {"name": "parameter3", "type": "uint32_t"}, u'参数3')
message_node.append(field_opc)
message_node.append(field_p1)
message_node.append(field_p2)
message_node.append(field_p3)
# 创建ElementTree对象
root_tree = ElementTree(root)
# 创建xml文件
root_tree.write(output_xml, encoding="utf-8", xml_declaration=True)
make_xml("./output.xml")
输出结果:
<?xml version='1.0' encoding='utf-8'?>
<messages><message name="SetDebugParam" id="100"><description>调试配置</description><field name="opc" type="uint8_t">操作码</field><field name="parameter1" type="uint32_t">参数1</field><field name="parameter2" type="uint32_t">参数2</field><field name="parameter3" type="uint32_t">参数3</field></message></messages>
5.3. 格式化xml文件
# xml格式化,调整缩进和换行; indent:缩进 newline: 换行 level: 缩进级别
def pretty_xml(element, indent, newline, level=0):
if element is not None: # 判断element是否有子元素
if (element.text is None) or element.text.isspace(): # 如果element的text没有内容
element.text = 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:
# 如果不是list的最后一个元素,说明下一个行是同级别元素的起始,缩进应一致
if temp.index(subelement) < (len(temp) - 1):
subelement.tail = newline + indent * (level + 1)
# 如果是list的最后一个元素, 说明下一行是母元素的结束,缩进应该少一个
else:
subelement.tail = newline + indent * level
pretty_xml(subelement, indent, newline, level=level + 1) # 对子元素进行递归操作
def make_xml():
...
# 格式化xml树
pretty_xml(root, '\t', '\n')
# 创建ElementTree对象
root_tree = ElementTree(root)
# 创建xml文件
root_tree.write(output_xml, encoding="utf-8", xml_declaration=True)
输出结果:
<?xml version='1.0' encoding='utf-8'?>
<messages>
<message name="SetDebugParam" id="100"><description>调试配置</description>
<field name="opc" type="uint8_t">操作码</field>
<field name="parameter1" type="uint32_t">参数1</field>
<field name="parameter2" type="uint32_t">参数2</field>
<field name="parameter3" type="uint32_t">参数3</field>
</message>
</messages>
5.4. 修改节点
#!/usr/bin/env python
from xml.etree.ElementTree import ElementTree,Element,SubElement
# 修改节点text
def change_node_text_by_tag(nodelist, tag, text):
for node in nodelist:
if node.tag == tag:
node.text = text
# 修改/新增/删除节点属性及属性值
def change_node_arrtib(nodelist, kv_map, is_delete=False):
for node in nodelist:
for key in kv_map:
if is_delete:
if key in node.attrib:
del node.attrib[key]
else:
node.set(key, kv_map.get(key))
# 修改节点属性,10进制数字改为16进制
def change_node_attrib_dec_to_hex(nodelist, kv_map):
for node in nodelist:
for key in kv_map:
node.set(key, str(hex(int(node.attrib[key], 10))))
# 删除子对象
def del_node_by_tag(nodelist, tag):
for node in nodelist:
if node.tag == tag:
nodelist.remove(node)
# 修改文件
def modify_msg(input_xml, output_xml):
node_item = {}
# 读取并解析xml文件
tree = ElementTree()
tree.parse(input_xml)
# 查找某个路径匹配的所有节点
msg_list = tree.findall("message")
# 修改message id 为16进制
change_node_attrib_dec_to_hex(msg_list, {"id": ""})
for msg in msg_list:
# 删除description子对象
del_node_by_tag(msg, "description")
# 修改field type 为 int32_t
change_node_arrtib(msg, {"type": "int32_t"})
# 新增属性
change_node_arrtib(msg, {"direction": "down"})
# 删除属性
change_node_arrtib(msg, {"name":""}, True)
# 创建xml文件
tree.write(output_xml, encoding="utf-8", xml_declaration=True)
modify_msg("./test.xml", "./test_new.xml")
输出结果:
<?xml version='1.0' encoding='utf-8'?>
<messages>
<message name="SetDebugParam" id="0x64">
<field type="int32_t" direction="down">操作码</field>
<field type="int32_t" direction="down">参数1</field>
<field type="int32_t" direction="down">参数2</field>
<field type="int32_t" direction="down">参数3</field>
</message>
</messages>
本文来自博客园,作者:流翎,转载请注明原文链接:https://www.cnblogs.com/hjx168/p/17750124.html