[快学Python3]XML解析处理 - Element Tree

概述

本文就是python xml解析进行讲解,在python中解析xml有很多种方法,本文通过实例来讲解如何使用ElementTree来解析xml。对于其他的xml解析方法,请自行去查找资料。

请注意,本文不是ElementTree手册,不会将所有的特性进行演示,笔者从实际用到的一些关键特性进行实例演示,对于其他特性,大家可以参见官方文档学习和了解:

https://docs.python.org/3/library/xml.etree.elementtree.html

什么是ElementTree

ElementTree是Python提供解析xml的标准库,ElementTree中每个节点(即Element)具有如下属性:

  • tag: string对象,标识该元素类型
  • attrib:dictionnary对象,标识该元素属性
  • text:string对象,标识该元素的文本
  • tail:string对象,标识该元素可选的尾字符串
  • child elements: 标识子节点

注:Element类型是一种灵活的容器对象,用于在内存中存储结构化数据。

使用ElementTree的标准方式为:

try:    
    # 若想加快速度,可以使用C语言编译的API xml.etree.cElementTree。
    import xml.etree.cElementTree as ET
except ImportError:    
    import xml.etree.ElementTree as ET

或者直接:

import xml.etree.ElementTree as ET

从文件加载xml进行解析

本节通过加载一个已存在于硬盘的xml文件,示例演示,直接看代码。

将下列内容保存至本地任何目录下: data_demo.xml:

<?xml version="1.0"?>
<data>
    <country name="Liechtenstein">
        <rank>1</rank>
        <year>2008</year>
        <gdppc>141100</gdppc>
        <neighbor name="Austria" direction="E"/>
        <neighbor name="Switzerland" direction="W"/>
    </country>
    <country name="Singapore">
        <rank>4</rank>
        <year>2011</year>
        <gdppc>59900</gdppc>
        <neighbor name="Malaysia" direction="N"/>
    </country>
    <country name="Panama">
        <rank>68</rank>
        <year>2011</year>
        <gdppc>13600</gdppc>
        <neighbor name="Costa Rica" direction="W"/>
        <neighbor name="Colombia" direction="E"/>
    </country>
</data>

下面我们解析上述data_demo.xml文档进行读、增、修改、删除操作

# -*- coding:utf-8 -*-

__author__ = '苦叶子'

try:    
    # 若想加快速度,可以使用C语言编译的API xml.etree.cElementTree。
    import xml.etree.cElementTree as ET
except ImportError:
    import xml.etree.ElementTree as ET
   
   
if __name__ == "__main__":

    print("解析本地data_demo.xml文档")    
    # 加载xml文件
    tree = ET.parse("data_demo.xml")    
    
    # 获取根节点, 并打印节点文本:data
    root = tree.getroot()
    print(root.tag)    

    # 遍历输出country及其name属性
    for child in root:
        print(child.tag, "name:" ,child.attrib["name"])    
    
    # 遍历rank节点
    # 我们借助iter迭代器来进行全迭代查找感兴趣的节点
    # 输出节点tag及其文本
    print("使用iter迭代器查找目标节点")
        for rank in root.iter("rank"):
            print(rank.tag, " - ", rank.text)    

    # 换一种方式来遍历rank节点
    # 我们借助findall和find方法来查找感兴趣的节点
    # 输出节点tag及其文本
    # 注意:findall只能查找从当前节点的子节点查找目标节点
    print("使用findall查找目标节点")    
    # 使用findall查找所有country节点,用于遍历
    for country in root.findall("country"):
        #print(country)
        # 使用find从country节点中查找rank节点
        rank = country.find("rank")
        print(rank.tag, " - ", rank.text)    
        
    # 把所有的rank的文本都修改为: 开源优测
    for rank in root.iter("rank"):
        rank.text = "开源优测"
        rank.set('updated', 'yes')    
    
    # 把修改后的rank的文本重新遍历打印出来,这时应该打印出: 开源优测
    for rank in root.iter("rank"):
        print(rank.text)    

    # 给所有的country新增一个<url>www.testingunion.com</url>节点
    for country in root.iter("country"):        
        # 创建一个节点
        url = ET.Element("url")        
        #print(url)

        # 给节点url的text赋值
        url.text = "www.testingunion.com"

        # 将url节点追加到country节点下
        country.append(url)    
        
    # 打印下整个xml出来看看是不是所有country节点都新增了一个url节点
    for country in root.iter("country"):        
        # 查找url节点
        url = country.find("url")        

        # 打印url的text
        print(url.text)    
    
    # 删除year节点
    for country in root.iter("country"):
        year = country.find("year")    
        
        # 如果year节点存在,则删除
        if year is not None:
            print("删除了一个year节点")
            country.remove(year)    
        
            
    # 保存上述 修改、新增、删除后的xml到 data_demo_new.xml中
    # 大家自己打开data_demo_new.xml文档看修改、新增、删除的节点是否有效
    tree.write("data_demo_new.xml", encoding="utf-8")

注: 用ET.fromstring("xml格式字符串") 替换ET.parse("data_demo.xml"),后续其他代码不变,即可实现对xml格式的字符串进行遍历读取、新增、修改和删除动作。

xpath支持

通过上面的实例我们基本学会了怎么对xml文档/xml格式的字符串进行遍历、新增、修改和删除操作,但对于xml怎么能缺少xpath的支持。

在ElementTree中,提供了良好的xpath特性支持,下面看一个实例

# -*- coding:utf-8 -*-

__author__ = '苦叶子'
try:    
    # 若想加快速度,可以使用C语言编译的API xml.etree.cElementTree。
    import xml.etree.cElementTree as ET
except ImportError:    
    import xml.etree.ElementTree as ET


if __name__ == "__main__":
    print("Element Tree XPath特性支持示例")    
    
    # 加载xml文件
    tree = ET.parse("data_demo.xml")    

    # 获取根节点, 并打印节点文本:data
    root = tree.getroot()    
    
    # 选择当前节点, 返回的是当前节点对象列表
    print("选择当前节点")
    data = root.findall(".")    
    for d in data:
        print(d.tag)    
    
    # 选择所有country节点
    print("选择所有country节点方法一")
    countrys = root.findall(".//country")    
    for country in countrys:
        print(country.tag, " ", country.attrib["name"])

    print("选择所有country节点方法二")
    countrys = root.findall("country")    
    for country in countrys:
        print(country.tag, " ", country.attrib["name"])

    print("选择name属性为Panama的country节点")
    countrys = root.findall(".//*[@name='Panama']")
    for country in countrys:
        print(country.tag, " ", country.attrib["name"])   
    
    # name属性为Panama的country下的year节点
    print("name属性为Panama的country下的year节点")
    years = root.findall(".//country[@name='Panama']/year")    
    for year in years:
        print(year.text)    
    
    # 通过索引来选择country节点,选择第一个country节点
    # 注意索引从 1 开始
    print("通过索引来选择country节点,选择第一个country节点")
    country = root.findall(".//country[1]")    
    for c in country:
        print(c.tag, " ", c.attrib["name"])    
    
    # 通过子节点的文本内容来选择节点
    # 选择子节点gdppc且其文本为59900 的country节点
    # 请注意这返回的是gdppc的父节点
    print("通过子节点的文本内容来选择节点")
    gdppc = root.findall(".//*[gdppc='59900']")    
    for gd in gdppc:
        print(gd.tag)

小结

本文就ElementTree解析xml的遍历、新增、修改、删除等操作进行了实例演示,并演示了其对XPath选择器的支持,但要注意的是其对XPath的支持是有限制的,并不支持所有的XPath语法。

原文发布于微信公众号 - 开源优测(DeepTest)

原文发表时间:2017-07-04

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏SpringBoot

一个密码复杂度的验证js

在项目开发中,要求密码进行复杂度限制,现帖出来跟大家做个分享。 密码复杂要求:1、长度大于8          2、密码必须是字母大写,字母小写,数字,特殊...

4033
来自专栏有趣的django

7.python常用模块

time模块 常用表示时间方式: 时间戳,格式化的时间字符串,元组(struct_time) UTC(Coordinated Universal Time,世界...

48211
来自专栏海天一树

小朋友学C语言(42):gets和fgets

这里可以看出来,定义了s的长度为3,但是用gets()输入字符串的时候,并不会去检查字符串的长度,所以导致char的值不是a,而是”uvwxyz”中的第四个字符...

1371
来自专栏海说

早期(编译期)优化

  相当多新生的java语法特性,都是靠编译器的“语法糖”来实现,而不是依赖虚拟机的底层改进来支持,java中即时编译器地运行期的优化过程对于程序运行来说更重要...

2030
来自专栏好好学java的技术栈

并发基础篇(二):Thread类的API总结

1194
来自专栏大内老A

ASP.NET MVC的Model元数据提供机制的实现

在前面的介绍中我们已经提到过表示Model元数据的ModelMetadata对象最终是通过一个名为ModelMetadataProvider的组件提供的,接下来...

2186
来自专栏python3

python3--模块collections,time,random,sys

有如下值集合[11,22,33,44,55,66,77,88,99,90......],将所有大于66的值保存至字典的第一个key中,小于66的值保存至第二个k...

982
来自专栏CDA数据分析师

工具 | 一些实用的 python 小建议

给dict设置默认值 这样能设置所有key的默认值为[],包括新添的key ? setdefault一次只能设置一个值,但好处是能使用链式语法,但default...

2065
来自专栏有趣的Python

代码模板:python-基础-5(菲波那切数列)

选自python高效开发实战。 # -*- coding: utf-8 -*- #!/usr/bin/env python ## linux系统告诉系统pyth...

3236
来自专栏java一日一条

细说 MySQL 之 MEM_ROOT

这篇文章会详细解说MySQL中使用非常广泛的MEM_ROOT的结构体,同时省去debug部分的信息,仅分析正常情况下,mysql中使用MEM_ROOT来做内存分...

781

扫码关注云+社区

领取腾讯云代金券