Python-XML模块

0 前言

>>返回Python系列文章目录<<

XML即可扩展标记语言,XML是互联网数据传输的重要工具,它可以跨越互联网任何的平台,不受编程语言和操作系统的限制,可以说它是一个拥有互联网最高级别通行证的数据携带者。

1 XML语法

<?xml version="1.0" encoding="utf-8" ?>
<root xmlns='http:autosar.org/schema/r4.0'>
    <part id="01" name="选项一">
        <name>我是徐茅山</name>
        <age>今年20岁</age>
        <sex></sex>
    </part>
    <part id="02" name="选项二">
        <name>我是李逍遥</name>
        <age>今年22岁</age>
        <sex></sex>
    </part>
</root>

1.1 文档申明

<?xml version="1.0" encoding="utf-8" standalone="yes" ?>

XML声明放在XML文档的第一行
version –文档符合XML1.0规范,我们学习1.0
encoding –文档字符编码,比如”gb2312”或者”utf-8”
standalone –文档定义是否独立使用。standalone=”no”为默认值。yes代表是独立使用,而no代表不是独立使用

1.2 元素和节点 element

<part id="01" name="选项一">
    <name>我是徐茅山</name>
    <age>今年20岁</age>
    <sex></sex>
</part>
  1. 元素包含标签tag,属性attrib(非必须)和文本text(最内侧元素才有)三要素

  2. 元素可以嵌套元素,每个XML文档必须有且只有一个根元素

  3. 标签分为开始标签和结束标签,标签必须遵守以下规范

区分大小写,
不能以数字或下划线”_”开头
不能包含空格,不能包含冒号

  1. 一个元素可以有多个属性,它的基本格式为:
<标签 属性名1="属性值1" 属性名2="属性值2">

属性值用双引号""或单引号''分隔
等号两边不能有空格
属性值不能包括<,>,&,如果一定要包含,也要使用实体字符

  1. 文本中出现的所有空格和换行,XML解析程序都会当做文本内容进行处理

  2. 具体的元素称为节点,元素是节点的类,节点是元素的实例。同一元素的节点具有相同的标签

1.3 命名空间

在 XML 中,当两个不同的文档使用相同的元素名时,就会发生命名冲突,而XML 命名空间提供避免元素命名冲突的方法。
XML命名空间被放置于元素的root标签之中,并有两种命名方式:

  1. 默认的命名空间
<root xmlns="namespaceURI">
  <part>
  </part>

其中,root是根节点,xmlns是固定术语(xml name space),"http:autosar.org/schema/r4.0"是唯一的namespaceURI

定义了默认的命名空间后,xml所有节点标签的全民都要加上前缀,比如part节点实际节点名称为:{http:autosar.org/schema/r4.0}part,为了书写方便,通常在python中这样定义:

xmlns = "{http:autosar.org/schema/r4.0}"
node = xmlns+"part"
  1. 显式的命名空间

<?xml version='1.0' encoding='UTF-8'?>
<nvd xmlns:vuln="http://bulabula" xmlns:cvss="http://abulaabula" xmlns="http://alulalula">
  <entry id="CVE-2011-0001">
     <vuln:cvss>
      <cvss:base_metrics>
        <cvss:score>5.0</cvss:score>
      </cvss:base_metrics>
    </vuln:cvss>
  </entry>
<nvd>

其中默认的命名空间为xmls,另外声明了两个命名空间xmlns:vuln和xmlns:cvss。
cvss:score节点被显式声明为cvss命名空间,需要这样访问:

cvss ={http://abulabula}”
node.find(cvss + 'score')

1.4 实体字符

XML有5个预定义的实体字符,用于文本非格式语句

实体字符说明
&lt;<
&gt;>
&amp;&
&apos;
&quot;"

1.5 CDATA节

  1. 如果要传递的内容包含大量的<,>,&或者“等一些特殊的不合法的字符,就要用到CDATA节,于把整段文本解释为纯字符数据而不是标记。CDATA节中可以输入任意字符(除]]>外),但是不能嵌套
<![CDATA[文本]]>

1.6 注释

<!--这是一个注释-->

1.7 处理指令

  1. 我们也可以使用css样式表来修饰XML文件

2 XML模块(内置库)

本文主要学习的 xml.etree.ElementTree 是python的XML处理模块,它提供了一个轻量级的对象模型。在使用 ET 模块时,需要import xml.etree.ElementTree的操作。ElementTree表示整个XML元素层级,而Element表示元素层级中的一个元素或者一个节点。

import xml.etree.ElementTree as ET

2.1 方法列表

ET模块说明
ET.ElementTree(root) -> ElementTree指定根节点,创建层级关系,返回ElementTree类
root->Element类
ET.parse(file) -> ElementTree读取XML文件的层级关系,返回ElementTree类
file->字符串
ET.Element(tag) -> Element创建根节点,返回Element类
tag->字符串
ET.SubElement(elem, tag) -> Element创建子节点,返回Element类
elem->现有节点Element类
tag->新节点的标签
ET.tostring(elem) -> str将节点转为文本,返回字符串
elem->Element类
self=ElementTree类说明
self.write(file)写入XML文件
file->字符串
self.getroot() -> Element得到根节点,返回Element类
Element类说明
self.set(key, value)添加、修改节点属性
key, value->字符串
self.find(path) -> Element通过层级路径查找子节点,只返回第一个,返回Element类
path->输入字符串
self.findall(path) -> list of Element通过层级路径查找子节点,用列表返回所有符合条件节点
path->输入字符串
self.iter(elem) -> Iter of Element查找所有符合条件子节点,返回迭代器
elem->Element类
self.clear()删除节点
self.text -> str
self.text = str
读写节点文本,字符串类型
self.tag -> str
self.tag = str
读写节点标签,字符串类型
self.attrib -> str
self.attrib = str
读写节点属性,字典类型

2.2 新建XML文件

import xml.etree.ElementTree as ET

root = ET.Element('root')       # 创建根节点

class1 = ET.SubElement(root, 'class')  # root节点下创建clss元素的class1节点

student1 = ET.SubElement(class1, 'student')
student1.set('id', '101')
student1.set('name', '徐茅山')       # set方法在原有属性后加上新属性,或者修改同名属性
age1 = ET.SubElement(student1, 'age')
age1.text = '22岁'
sex1 = ET.SubElement(student1, 'sex')
sex1.text = '男'

student2 = ET.SubElement(class1, 'student')
student2.attrib = {'id': '102', 'name': '朱小越'}  # attrib会完全替换原有属性
age2 = ET.SubElement(student2, 'age')
age2.text = '21岁'
sex2 = ET.SubElement(student2, 'sex')
sex2.text = '女'

class2 = ET.SubElement(root, 'class')

student3 = ET.SubElement(class2, 'student')
student3.attrib = {'id': '202', 'name': '李逍遥'}
age3 = ET.SubElement(student3, 'age')
age3.text = '20岁'
sex3 = ET.SubElement(student3, 'sex')
sex3.text = '男'

tree = ET.ElementTree(root)      # 以root为根节点创建层级关系
tree.write('simple.xml', encoding="utf-8", xml_declaration=True)  # 写入文件声明

用浏览器打开simple.xml文件
在这里插入图片描述

2.3 查找XML文件

2.3.1 按路径定位一个节点 getroot find

getroot()返回根节点

find()根据一个当前节点和层级路径,往下寻找指定元素的第一个节点

import xml.etree.ElementTree as ET

tree = ET.parse('simple.xml')

root = tree.getroot()                   # 查找根节点
print(root.tag)                         # 结果:root

elem1 = root.find('class')              # 绝对路径不包括root,只能搜索到第一个符合条件的节点
print(elem1.tag)                        # 结果:class
print(elem1.attrib)                     # 结果:{}
print(elem1.text)                       # 结果: None
elem2 = root.find('class/student')      # 绝对路径用/分割,只能搜索到第一个符合条件的节点
print(elem2.tag)                        # 结果:student
print(elem2.attrib)                     # 结果:{'id': '101', 'name': '徐茅山'}
print(elem2.text)                       # 结果:None
elem3 = elem1.find('student/age')       # 绝对路径不包括elem1,只能搜索到第一个符合条件的节点
print(elem3.tag)                        # 结果:age
print(elem3.attrib)                     # 结果:{}
print(elem3.text)                       # 结果:22岁

2.3.2 按路径遍历节点 findall

findall()根据一个当前节点和层级路径,往下寻找指定元素的所有节点,返回列表

import xml.etree.ElementTree as ET

tree = ET.parse('simple.xml')
root = tree.getroot()
elem1 = root.findall('class')         # 返回2个class节点的列表
elem2 = elem1[0].findall('student')   # 列表可以切片
for e in elem2:                       # 列表可以遍历
    print(e.attrib)

程序结果:

{'id': '101', 'name': '徐茅山'}
{'id': '102', 'name': '朱小越'}

2.3.3 按范围遍历节点 iter

iter()在当前节点下搜索指定元素的所有节点,无需层级路径,返回一个迭代器

import xml.etree.ElementTree as ET

tree = ET.parse('simple.xml')
root = tree.getroot()
elem1 = root.iter('age')
for e in elem1:
    print(e.text)

程序结果:

222120

2.3.4 打印节点 tostring

tostring()将节点转化成字符串格式输出

import xml.etree.ElementTree as ET

tree = ET.parse('simple.xml')
root = tree.getroot()
elem1 = root.findall('class/student')
for e in elem1:
    print(ET.tostring(e, encoding="unicode"))

程序结果:

<student id="101" name="徐茅山"><age>22</age><sex></sex></student>
<student id="102" name="朱小越"><age>21</age><sex></sex></student>
<student id="202" name="李逍遥"><age>20</age><sex></sex></student>

2.4 修改和删除XML数据

  1. 修改节点标签、属性和文本可直接用节点的tagattribtext属性,添加节点的属性用set()

  2. 删除节点用clear()

  3. 配合遍历可批量修改

import xml.etree.ElementTree as ET

tree = ET.parse('simple.xml')
root = tree.getroot()
elem1 = root.findall('class')
for e in elem1:
    e.tag = 'grade'    # 将class元素改名为grade元素

tree.write('simple.xml')

在这里插入图片描述
>>返回Python系列文章目录<<

3 findall()方法对XPath的支持

xml.etree.ElementTree中的findall()方法支持部分XPath语法

3.1 创建相对xpath

① 支持.作为当前节点tag,/作为下一级子节点tag分隔符。

root.findall("./country/neighbor")

② 所有实际tag,如果有定义namespace,都必须带有对应的namespace,不可省略

root.findall("./{namespace}country/{namespace}cneighbor")

③ 支持*表示任意节点tag,进行模糊匹配

root.findall("./*/neighbor")

④ 支持//表示任意间隔级子节点分隔符

root.findall(".//neighbor")

⑤ 支持..表示父节点(官方文档说支持,实测不支持,存疑)

root.findall("../country")

3.2 xpath的附加条件

① 支持[@attrib]表示筛选带有特定属性的节点,[@attrib!='value']表示筛选属性为特定值的节点,[@attrib!='value']表示筛选属性不为特定值的节点

root.findall(".//year[@name='Singapore']")
root.findall("./*[@name='Singapore']/year")

② 支持[.='text']表示筛选具有对应text内容的节点
[.!='text']表示筛选不具有对应text内容的节点

root.findall(".//year[.='2011']")
root.findall("./*[.='2011']/year")

③ 支持[tag]表示筛选具有对应tag子节点(必须是紧挨着下一级)的节点
[tag='text']表示筛选具有对应tag和text内容子节点(必须是紧挨着下一级)的节点
[tag!='text']表示筛选具有对应tag,但是不具有对应text内容子节点(必须是紧挨着下一级)的节点

root.findall("./country[year='2011']")

3.3 按list定位子节点

① XPath支持将节点视为自身所有子节点的list,可以直接使用下标返回对应的子节点

node = root[0][1]
  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值