前言
XML的解析方法有很多,但是本教程值介绍xml.etree.cElementTree的解析方法
因为它使用C语言实现,因为它的速度要快很多,而且内存消耗也要少很多。所以
学这个方法就够了。
什么是XML?
将XML文档解析为树(tree)
我们先从基础讲起。XML是一种结构化、层级化的数据格式,最适合体现XML的数据结构就是树。ET提供了两个对象:ElementTree将整个XML文档转化为树,Element则代表着树上的单个节点。对整个XML文档的交互(读取,写入,查找需要的元素),一般是在ElementTree层面进行的。对单个XML元素及其子元素,则是在Element层面进行的。下面我们举例介绍主要使用方法。
我们使用下面的XML文档,作为演示数据:
<?xml version="1.0"?>
<doc>
<branch name="codingpy.com" hash="1cdf045c">
text,source
</branch>
<branch name="release01" hash="f200013e">
<sub-branch name="subrelease01">
xml,sgml
</sub-branch>
</branch>
<branch name="invalid">
<sub-branch name="helloworld" hash="4242">
哈哈哈
</sub-branch>
</branch>
</doc>
树的结构
XML文档—-读操作
import xml.etree.cElementTree as ET
xml = ET.ElementTree(file='xmltest.xml')
获取根节点
root = xml.getroot()
获取了根节点,我们来看看根节点的信息
print(root.tag,root.attrib)
输出:
doc {}
一个节点的信息包括三个部分:tag attrib text
根节点是一个特殊的节点,所以它只有tag
以下面的节点为例:
branch {'name': 'codingpy.com', 'hash': '1cdf045c'}
text,source
tag = branch
attrib = {'name': 'codingpy.com', 'hash': '1cdf045c'}
text = text,source
查看子节点信息
这里我们来看看根节点的子节点信息
for child in root:
print(child.tag,child.attrib,child.text)
输出:
branch {'name': 'codingpy.com', 'hash': '1cdf045c'}
text,source
branch {'name': 'release01', 'hash': 'f200013e'}
branch {'name': 'invalid'}
可以看到输出了root节点下面的三个branch节点,第一个branch是有text,而其他两个没有text信息
通过索引访问节点
son = root[1][0]
print(son.tag,son.attrib,son.text)
输出:
sub-branch {'name': 'subrelease01'}
xml,sgml
当然,要通过索引的方式访问节点,我们必须清楚地知道树的结构。
遍历整个XML树
for elem in root.iter():
print(elem.tag,elem.attrib,elem.text)
输出:
doc {}
branch {'name': 'codingpy.com', 'hash': '1cdf045c'}
text,source
branch {'name': 'release01', 'hash': 'f200013e'}
sub-branch {'name': 'subrelease01'}
xml,sgml
branch {'name': 'invalid'}
sub-branch {'name': 'helloworld', 'hash': '4242'}
哈哈哈
注意,这里的root.iter( )其实返回的是一个迭代器
遍历指定的节点
for elem2 in root.iter(tag = 'sub-branch'):
print(elem2.tag,elem2.attrib,elem2.text)
输出:
sub-branch {'name': 'subrelease01'}
xml,sgml
sub-branch {'name': 'helloworld', 'hash': '4242'}
哈哈哈
这里找出了所有tag = ‘sub-branch’的节点
root.iter( )的函数声明
def iter(self, tag=None):
所以,这里的遍历指定节点只能指定tag
按路径查找第一个匹配的子节点
函数声明:
find(path, namespaces=None) method of xml.etree.ElementTree.Element instance
需要手动输入路径
elem3 = root.find('branch/sub-branch')
print(elem3.tag,elem3.attrib,elem3.text)
输出:
sub-branch {'name': 'subrelease01'}
xml,sgml
按路径查找所有匹配的节点
遍历迭代器方式:
声明:def iterfind(self, path, namespaces=None):
for elem4 in root.iterfind('branch/sub-branch'):
print(elem4.tag,elem4.attrib,elem4.text)
输出:
sub-branch {'name': 'subrelease01'}
xml,sgml
sub-branch {'name': 'helloworld', 'hash': '4242'}
哈哈哈
遍历列表方式:
声明:def findall(self, path, namespaces=None):
for elem5 in root.findall('branch/sub-branch'):
print(elem5.tag,elem5.attrib,elem5.text)
输出:
sub-branch {'name': 'subrelease01'}
xml,sgml
sub-branch {'name': 'helloworld', 'hash': '4242'}
哈哈哈
遍历条件具体到属性attrib (路径+属性)
for elem6 in root.iterfind('branch/sub-branch[@name="helloworld"]'):
print(elem6.tag,elem6.attrib,elem6.text)
输出:
sub-branch {'name': 'helloworld', 'hash': '4242'}
哈哈哈
findall( )用法也一样。
findall()和iterfind()作用都一样,只不过前者返回列表,后者返回的迭代器。也是说前者可以进行索引,后者不能够索引。
XML文档—写操作
增加节点属性
声明:
def set(self, key, value):
elem = root.find('branch')
elem.set('haha','hehe')
print(elem.tag,elem.attrib,elem.text)
elem2 = root.find('branch')
print(elem2.tag,elem2.attrib,elem2.text)
输出:branch {'name': 'codingpy.com', 'hash': '1cdf045c', 'haha': 'hehe'}
text,source
branch {'name': 'codingpy.com', 'hash': '1cdf045c', 'haha': 'hehe'}
text,source
修改节点信息
elem = root.find('branch/sub-branch')
elem.tag = 'test-branch'
elem.attrib = {'name':'test','hash':'123'}
elem.text = '\n这只是一个测试\n'
print(elem.tag,elem.attrib,elem.text)
输出:
test-branch {'name': 'test', 'hash': '123'}
这只是一个测试
现在修改之后,我们需要保存至文件,才能够永久的保存,不然只是保存在内存里面。
写入信息到xml文件
声明:
write(file_or_filename, encoding=None, xml_declaration=None, default_namespace=None, method=None, *, short_empty_elements=True) method of xml.etree.ElementTree.ElementTree instance
一句话即可
xml.write('xmltest.xml')
构建一个XML文档
a1 = ET.Element('elem')#创建节点
b1 = ET.SubElement(a1,'elem2')#创建某个节点的子节点
b2 = ET.SubElement(a1,'elem2')
b2.text = 'I love you'#添加正文
a2 = ET.Element('elem')
root = ET.Element('root')#创建根节点
root.extend((a1,a2))#把a1,a2添加到根节点
tree = ET.ElementTree(root)#根据根节点创建树
tree.write('treexml.xml')#写入到xml文档
for t in tree.iter():
print(t.tag,t.attrib,t.text)
xml文档:
<root>
<elem>
<elem2 />
<elem2>
I love you
</elem2>
</elem>
<elem />
</root>
本文有待更新,之后会添加更多的使用方法。