• Python3 XML处理模块详解


    目录

    一:XML文件格式

    二:ElementTree解析XML文件

    三:Element之查找

    四:Element之修改

    五:Element之删除

    六:Element之增加

    七:Element之排序


            xml是一种固有的分层数据格式,最自然的表示方式是解析成树状,在配置文件中很多采用xml的形式进行配置存储。在xml的日常维护中,经常会涉及到对xml文件的增删改查,如果从零开始对xml进行硬解析也是一件很麻烦的事情。

            Python3内置了xml处理模块xml.etree.ElementTree 可以帮助我们去解析xml,并支持对xml的增删改查。下面我们对该模块从增删改查四个方面进行探索

    一:XML文件格式

            xml总体看上去就是一个树状的分层结构,下面给出一个xml文件的样例,后面针对xml的增删改查操作就以该xml为例:

    1. "1.0" encoding="utf-8"?>
    2. <addr_info id="中国">
    3. <R1 type="上海">
    4. <device_type>黄埔区device_type>
    5. <username>adminusername>
    6. <people_num>一百万people_num>
    7. <company>zte.com.cncompany>
    8. R1>
    9. <SW3 type="南京">
    10. <device_type>江宁区device_type>
    11. <username>adminusername>
    12. <people_num>两百万people_num>
    13. <company>baidu.com.cncompany>
    14. SW3>
    15. addr_info>

    二:ElementTree解析XML文件

    我们用ElementTree去解析上面的xml文件,具体用法如下:

    1. import xml.etree.ElementTree as ET
    2. tree = ET.parse('eg.xml')#直接读取xml文件,形成ElementTree结构
    3. root = tree.getroot() # 获取root tag
    4. print('tag:',root.tag) # 打印root的tag
    5. print('attrib:',root.attrib) # 打印root的attrib
    6. # 使用root索引访问标签的值,[0]是R1标签,[0]是R1标签中的第一个标签device_type, .text是取这个标签的值,自然值就是cisco_ios
    7. print(root[0][0].text)
    8. for child in root: # 打印root的child层的tag和attrib
    9. print(child.tag, child.attrib)

    运行结果:

    1. tag: addr_info
    2. attrib: {'id': '中国', 'topic': 'ftz'}
    3. 黄埔区
    4. R1 {'type': '上海'}
    5. SW3 {'type': '南京'}

    我们可以通过dir来查看root支持的属性

    1. ['__class__', '__copy__', '__deepcopy__', '__delattr__', '__delitem__',
    2. '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__',
    3. '__getitem__', '__getstate__', '__gt__', '__hash__', '__init__',
    4. '__init_subclass__', '__le__', '__len__', '__lt__', '__ne__', '__new__',
    5. '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__',
    6. '__setstate__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'attrib',
    7. 'clear', 'extend', 'find', 'findall', 'findtext', 'get', 'getchildren',
    8. 'getiterator', 'insert', 'items', 'iter', 'iterfind', 'itertext', 'keys',
    9. 'makeelement', 'remove', 'set', 'tag', 'tail', 'text']

    Element常用属性如下:

    1、tag

    tag是str对象,表示xml标签,例子中的前后闭合的device_type

    2、attrib

    attrib是一个dict对象,表示xml属性,例子中的type="上海"

    3、text

    text就是xml数据标签包裹的内容,也是Element的内容,例子中的 admin,一百万

    4、child elements

    child elements则是xml一对标签中包含的子集,类似于上面例子中R1和SW3标签中包裹的内容

    三:Element之查找

    Element有很丰富的查找方法,总结如下:

    iter(tag=None) 遍历Element的child,可以指定tag精确查找
    findall(match) 查找当前元素tag或path能匹配的child节点
    find(match) 查找当前元素tag或path能匹配的第一个child节点
    get(key, default=None) 获取元素指定key对应的attrib,如果没有attrib,返回default。 

    我们用iter和findall为例来查找上述例子中的人口

    1. import xml.etree.ElementTree as ET
    2. tree = ET.parse('eg.xml')
    3. root = tree.getroot()
    4. #iter查找
    5. for addr in root.iter():
    6. if addr.tag == 'people_num':
    7. print("people_num=",addr.text)
    8. #findall查找
    9. for people in root.findall('R1'):
    10. peopleNum = people.find('people_num').text
    11. print("people_num=",peopleNum)
    12. for people in root.findall('SW3'):
    13. peopleNum = people.find('people_num').text
    14. print("people_num=",peopleNum)

    运行结果:

    四:Element之修改

    Element的修改方法如下:

    Element.text 直接修改字段
    Element.remove() 删除字段
    Element.set() 添加或修改属性attrib
    with Element.append() 添加新的child 

            我们将上海黄浦区的人口数从一百万改成一千万,首先需要找到R1节点,然后找到R1节点下的people_num的子节点,找到子节点对其内容进行修改,这就用到了上面提到的text属性,就是对text进行修改

    1. import xml.etree.ElementTree as ET
    2. tree = ET.parse('eg.xml')
    3. root = tree.getroot()
    4. for addr in root.iter('R1'):
    5. addr.find('people_num').text = '一千万'
    6. tree.write('./eg2.xml',encoding='utf-8')

    确认修改完毕后,需要使用ElementTree.write()方法写入,write的使用方法如下:

    五:Element之删除

    Element的删除方法如下:

    remove  移除节点

    我们还是以上面为例,删除整个SW3节点

    1. import xml.etree.ElementTree as ET
    2. tree = ET.parse('eg.xml')
    3. root = tree.getroot()
    4. for addr in root.findall('SW3'):
    5. root.remove(addr)
    6. tree.write('./eg2.xml',encoding='utf-8')

    那如果我想删除R1节点的子节点username呢,还没摸索出来,后续更新

    六:Element之增加

    Element的增加节点方法如下:

    ET.SubElement

    我们新增一个节点黄冈的节点,还有节点下面的子节点,方法如下:

    1. import xml.etree.ElementTree as ET
    2. xmlParse = ET.parse('eg.xml')
    3. root = xmlParse.getroot()
    4. tree = ET.ElementTree(root)
    5. #增加R3节点
    6. hubeiNode = ET.SubElement(root,'R3')
    7. hubeiNode.attrib = {'type':'黄冈'}
    8. #增加R3节点的子节点
    9. huanggang = ET.SubElement(hubeiNode,'device_type')
    10. huanggang.text = '黄梅县'
    11. huanggang2 = ET.SubElement(hubeiNode,'username')
    12. huanggang2.text = 'admin'
    13. huanggang3 = ET.SubElement(hubeiNode,'people_num')
    14. huanggang3.text = '五十万'
    15. huanggang4 = ET.SubElement(hubeiNode,'company')
    16. huanggang4.text = 'feidadun.com'
    17. tree.write('./eg2.xml', encoding='utf-8', xml_declaration=True, short_empty_elements=True)

    虽然达到了我们的目的,但是写入后都挤到一行了,不方便看,用下面的函数进行美化

    1. def pretty_xml(element, indent, newline, level=0): # elemnt为传进来的Elment类,参数indent用于缩进,newline用于换行
    2. if element: # 判断element是否有子元素
    3. if (element.text is None) or element.text.isspace(): # 如果element的text没有内容
    4. element.text = newline + indent * (level + 1)
    5. else:
    6. element.text = newline + indent * (level + 1) + element.text.strip() + newline + indent * (level + 1)
    7. # else: # 此处两行如果把注释去掉,Element的text也会另起一行
    8. # element.text = newline + indent * (level + 1) + element.text.strip() + newline + indent * level
    9. temp = list(element) # 将element转成list
    10. for subelement in temp:
    11. if temp.index(subelement) < (len(temp) - 1): # 如果不是list的最后一个元素,说明下一个行是同级别元素的起始,缩进应一致
    12. subelement.tail = newline + indent * (level + 1)
    13. else: # 如果是list的最后一个元素, 说明下一行是母元素的结束,缩进应该少一个
    14. subelement.tail = newline + indent * level
    15. pretty_xml(subelement, indent, newline, level=level + 1) # 对子元素进行递归操作

    最后的效果如下:

    附上全部代码:

    1. import xml.etree.ElementTree as ET
    2. def pretty_xml(element, indent, newline, level=0): # elemnt为传进来的Elment类,参数indent用于缩进,newline用于换行
    3. if element: # 判断element是否有子元素
    4. if (element.text is None) or element.text.isspace(): # 如果element的text没有内容
    5. element.text = newline + indent * (level + 1)
    6. else:
    7. element.text = newline + indent * (level + 1) + element.text.strip() + newline + indent * (level + 1)
    8. # else: # 此处两行如果把注释去掉,Element的text也会另起一行
    9. # element.text = newline + indent * (level + 1) + element.text.strip() + newline + indent * level
    10. temp = list(element) # 将element转成list
    11. for subelement in temp:
    12. if temp.index(subelement) < (len(temp) - 1): # 如果不是list的最后一个元素,说明下一个行是同级别元素的起始,缩进应一致
    13. subelement.tail = newline + indent * (level + 1)
    14. else: # 如果是list的最后一个元素, 说明下一行是母元素的结束,缩进应该少一个
    15. subelement.tail = newline + indent * level
    16. pretty_xml(subelement, indent, newline, level=level + 1) # 对子元素进行递归操作
    17. xmlParse = ET.parse('eg.xml')
    18. root = xmlParse.getroot()
    19. tree = ET.ElementTree(root)
    20. #增加R3节点
    21. hubeiNode = ET.SubElement(root,'R3')
    22. hubeiNode.attrib = {'type':'黄冈'}
    23. #增加R3节点的子节点
    24. huanggang = ET.SubElement(hubeiNode,'device_type')
    25. huanggang.text = '黄梅县'
    26. huanggang2 = ET.SubElement(hubeiNode,'username')
    27. huanggang2.text = 'admin'
    28. huanggang3 = ET.SubElement(hubeiNode,'people_num')
    29. huanggang3.text = '五十万'
    30. huanggang4 = ET.SubElement(hubeiNode,'company')
    31. huanggang4.text = 'feidadun.com'
    32. pretty_xml(root, ' ', '\n') # 执行美化方法 缩进为两个空格,'\n'换行
    33. tree.write('./eg2.xml', encoding='utf-8', xml_declaration=True, short_empty_elements=True)

    七:Element之排序

    1. import xml.etree.ElementTree as ET
    2. import re
    3. # 读取XML文件
    4. tree = ET.parse('test.xml')
    5. # 获取根元素
    6. root = tree.getroot()
    7. def sortkey(child):
    8. str = child.attrib.get('navtitle')
    9. if str:
    10. key = str[:5]
    11. if key.isdigit:
    12. return key
    13. else:
    14. return '0'
    15. # 获取所有子节点并进行排序
    16. root[:] = sorted(root, key=lambda child: sortkey(child))
    17. # 输出新的XML文件
    18. tree.write('test_sorted.xml',encoding='utf-8')

  • 相关阅读:
    wps批量删除空白单元格
    【Spring Security 系列】(六)入门案例中各组件的实现类
    Python 列表切片陷阱:引用、复制与深复制
    使用 MySQL 命令备份,恢复数据库
    Google Earth Engine APP(GEE)——一个可以时序动画监测的动态APP
    「PAT乙级真题解析」Basic Level 1107 老鼠爱大米 (问题分析+完整步骤+伪代码描述+提交通过代码)
    ke11介绍本地,会话存储
    数图可视化品类空间管理系统入编《零售门店数字化赋能专项报告(2024年)》
    shell 脚本部署 helm
    JVM第三讲:JVM 基础-字节码的增强技术详解
  • 原文地址:https://blog.csdn.net/qq_27071221/article/details/132838534