文章目录
- 简介
- ElementTree与Elment
- 解析XML
- 遍历元素
- 修改XML文件
- 使用iterparse处理大文件
转载请注明原始链接:
后续此博客不再更新,欢迎大家搜索关注微信公众号“测开之美”,测试开发工程师技术修炼小站,持续学习持续进步。
简介
XML是被设计用来传输和存储数据的可扩展标记语言,Python中可以使用xml.etree.ElementTree操作XML文件。
Python 2.7采用ElementTree 1.3版本。xml.etree.ElementTree的更高效、占用内存更少的C语言版本的实现是xml.etree.cElementTree。
ElementTree与Elment
XML按照树型结构组织,ET有两种类来表示这种组织结构:ElementTree表示整个XML树,Element表示树上的单个节点。操作整个XML文档时使用ElementTree类,比如读写XML文件。操作XML元素及其子元素时使用Element类。Element是一个灵活的容器对象,在内存中存储层次化的数据结构。
每个元素包含如下属性:
- tag:表示元素类型的字符串。
- attrib:以Python字典形式存储的元素属性。
- text:开始标签和第一个子元素之间的字符串或开始标签和结束标签之间的字符串或None。
- tail:结束标签和下一个标签之间的字符串或None。
- 子元素:以Python序列的形式存储。
创建Element元素,使用Element()构造器或SubElement()工厂函数。
解析XML
比如test.xml内容为:
<?xml version="1.0"?>
<bookstore author="mars loo">
<book>
<name>LeaderF</name>
<price>12.33</price>
</book>
<book>
<name>YCM</name>
<price>11.91</price>
</book>
</bookstore>
可以调用ET.parse(filename)将XML文档解析为ElementTree对象,调用ElementTree.getroot()获取Element类型的树根,然后分别访问树根元素的tag、attrib、text、tail等属性:
try:
import xml.etree.cElementTree as ET
except ImportError:
import xml.etree.ElementTree as ET
tree = ET.parse('test.xml')
root = tree.getroot()
print "Tag:", root.tag, "Attributes:", root.attrib, "Text:", root.text.strip(), "Tail:", root.tail
运行结果:
Tag: bookstore Attributes: {'author': 'mars loo'} Text: Tail: None
注意,如果test.xml文件的第2行是如下内容:
<bookstore author="mars loo"><book>
则上面的代码中root.text
的类型是None。
使用tree = ET.ElementTree(file='test.xml')
与使用tree = ET.parse('test.xml')
效果一样。如果使用ET.fromstring()方法解析,则直接返回Element类型的树根元素。如果一个Element对象有子元素,可以直接遍历,也可以使用下标访问:
try:
import xml.etree.cElementTree as ET
except:
import xml.etree.ElementTree as ET
xml_string = '''<?xml version="1.0"?>
<bookstore author="mars loo">
<book id="1">
<name>LeaderF</name>
<price>12.33</price>
</book>
<book id="2">
<name>YCM</name>
<price>11.91</price>
</book>
</bookstore>'''
root = ET.fromstring(xml_string)
for child in root:
print "Tag:", child.tag, "Attributes:", child.attrib
print "Book 2's price", root[1][1].text.strip()
运行结果:
Tag: book Attributes: {'id': '1'}
Tag: book Attributes: {'id': '2'}
Book 2's price 11.91
遍历元素
Element类和ElementTree类都有iter()方法可以递归遍历元素/树的所有子元素,比如:
for child in root.iter(): //root是Element对象
print "Tag:", child.tag, "Attributes:", child.attrib, "Text:", child.text.strip()
使用tag参数可以遍历指定tag的元素:
for child in tree.iter(tag='price'): //tree是ElementTree对象
print "Tag:", child.tag, "Attributes:", child.attrib, "Text:", child.text.strip()
Element.findall(match)方法通过tag名字或xpath匹配第一层子元素,按照子元素顺序以列表形式返回所有匹配的元素。
Element.find(match)方法通过tag名字或xpath在第一层子元素中查找第一个匹配的元素,返回匹配的元素或None。
Element.get(key, default=None)返回元素名字为key的属性值,如果没有找到,返回None或设置的默认值。
修改XML文件
ElementTree.write(filename)方法可以方便的将ElementTree对象写入XML文件。
可以通过调用Element对象不同的方法修改Element对象,比如:
- Element.text=value可以直接修改其text属性。
- Element.tail=value可以直接修改其tail属性。
- Element.set(key, vlaue)可以添加新的attrib。
- Element.append(subelement)可以添加新的子元素。
- Element.extend(subelements)添加子元素的列表(参数类型是序列)。
- Element.remove(subelement)可以删除子元素。
将所有图书的价格加1,给price元素增加一个updated="true"
的属性,同时增加一个内容为"tail"
的tail:
tree = ET.parse('test.xml')
for child in tree.iter(tag = 'price'):
child.text = str(float(child.text.strip()) + 1)
child.tail = "tail"
child.set("updated", "true")
tree.write('new.xml')
new.xml内容为:
<bookstore author="mars loo">
<book>
<name>LeaderF</name>
<price updated="true">13.33</price>tail</book>
<book>
<name>YCM</name>
<price updated="true">12.91</price>tail</book>
</bookstore>
将所有图书元素的price元素删除,增加出版社press元素,press元素的text属性内容是CTS
:
bookstore = ET.parse('test.xml')
for book in bookstore.findall('book'):
book.remove(book.find('price'))
press = ET.Element('press')
press.text = "CTS"
book.append(press)
bookstore.write('new2.xml')
new2.xml内容为:
<bookstore author="mars loo">
<book>
<name>LeaderF</name>
<press>CTS</press></book>
<book>
<name>YCM</name>
<press>CTS</press></book>
</bookstore>
使用ET.SubElement(parent, tag_name)可以快速建立子元素关系,使用ET.dump(elem)可以输出elem的内容到标准输出(elem可以是一个Element对象或ElementTree对象):
root = ET.Element('root')
a = ET.SubElement(root, 'a')
b = ET.SubElement(root, 'b')
c = ET.SubElement(root, 'c')
tree = ET.ElementTree(root)
ET.dump(tree)
运行输出:
<root><a /><b /><c /></root>
使用iterparse处理大文件
ET.parse(filename)一次性将整个XML文件加载到内存,ET.iterparse(filename)采用增量形式加载XML数据,占据更小的内存空间。如果test.xml包含非常多本书我们想统计书本数量,可以采用iterparse()高效处理:
count = 0
for event, elem in ET.iterparse('test.xml'):
if event == 'end':
if elem.tag == "book":
count += 1
elem.clear() //重置元素(删除所有子元素、清除所有attrib、将text和tail设置为None)
print count