Python自动化实战:ElementTree库快速入门指南

74 阅读3分钟

一、ElementTree 库简介

xml.etree.ElementTree 是 Python 处理 XML 的标准库,它:

  • ✅ 轻量高效:比 DOM 解析器更简单,比 SAX 解析器更易用
  • ✅ 内置模块:无需安装任何第三方包
  • ✅ Pythonic API:使用方式符合 Python 习惯

二、核心操作快速上手

1. 解析 XML:读取与理解

import xml.etree.ElementTree as ET

# 从字符串解析
xml_string = '''
<bookstore>
    <book category="编程">
        <title>Python编程从入门到实践</title>
        <author>Eric Matthes</author>
        <year>2016</year>
        <price>89.00</price>
    </book>
</bookstore>
'''
root = ET.fromstring(xml_string)  # 获取根元素

# 从文件解析
tree = ET.parse('books.xml')      # 解析文件
root = tree.getroot()             # 获取根元素

print(f"根元素标签: {root.tag}")   # 输出: bookstore

2. 遍历与访问元素

# 遍历所有子元素
for child in root:
    print(f"子元素: {child.tag}, 属性: {child.attrib}")
    # 访问孙子元素
    for subchild in child:
        print(f"  {subchild.tag}: {subchild.text}")

# 访问特定元素的文本
title = root.find('book/title')  # 查找第一个匹配的元素
if title is not None:
    print(f"书名: {title.text}")

# 查找所有符合条件的元素
all_books = root.findall('book')  # 查找所有book元素
print(f"找到 {len(all_books)} 本书")

1. 基本查找

# 查找直接子元素
element = root.find('child')  # 只找直接子节点

# 递归查找所有子孙元素
element = root.find('.//child')  # 任何层级的child元素

# 带路径的查找
element = root.find('parent/child')  # 特定路径

2. 带命名空间的查找

# 方法1:使用大括号语法(你的例子中的方法)
namespace = '{http://www.example.com/ns}'
element = root.find(f'.//{namespace}status')

# 方法2:使用命名空间字典
ns = {'ns': 'http://www.example.com/ns'}
element = root.find('.//ns:status', ns)

3. 使用XPath表达式(findall支持更多)

# 查找具有特定属性的元素
element = root.find('.//item[@id]')  # 有id属性的item
element = root.find('.//item[@id="123"]')  # id为123的item

# 查找特定文本内容的元素
element = root.find('.//name[text()="John"]')

# 查找第n个元素
element = root.find('.//item[1]')  # 第一个item(索引从1开始)

3. 创建 XML 文档

# 创建根元素
root = ET.Element("bookstore")

# 创建子元素并添加属性
book = ET.SubElement(root, "book")
book.set("category", "编程")

# 添加更多子元素
title = ET.SubElement(book, "title")
title.text = "Python核心编程"
author = ET.SubElement(book, "author")
author.text = "Wesley Chun"

# 创建XML树并写入文件
tree = ET.ElementTree(root)
tree.write("new_book.xml", encoding="utf-8", xml_declaration=True)

print("XML文件创建成功!")

4. 修改 XML 内容

# 修改元素文本
for price in root.iter('price'):  # iter()遍历所有price元素
    old_price = float(price.text)
    price.text = str(old_price * 0.9)  # 打9折
    price.set('discount', '10%')       # 添加新属性

# 删除元素
for book in root.findall('book'):
    year = book.find('year')
    if year is not None and int(year.text) < 2010:
        root.remove(book)  # 删除2010年以前的书

# 保存修改
tree.write('updated_books.xml')

5. 查找元素的多种方式

# 1. 使用XPath-like语法(有限支持)
expensive_books = root.findall("book[price>50]")  # 价格>50的书

# 2. 遍历所有特定标签
for author in root.iter('author'):
    print(f"作者: {author.text}")

# 3. 复杂条件查找
for book in root.findall('book'):
    price = float(book.find('price').text)
    category = book.get('category')
    if price > 80 and category == '编程':
        print(f"昂贵的编程书: {book.find('title').text}")

三、实用技巧与注意事项

处理命名空间

# 带命名空间的XML
ns_xml = '''
<root xmlns:bk="http://example.com/books">
    <bk:book>
        <bk:title>Python学习手册</bk:title>
    </bk:book>
</root>
'''

# 注册命名空间前缀(方便查找)
namespaces = {'bk': 'http://example.com/books'}
root = ET.fromstring(ns_xml)
title = root.find('bk:book/bk:title', namespaces)

处理大型 XML 文件

# 使用迭代解析,节省内存
for event, elem in ET.iterparse('large_file.xml', events=('start', 'end')):
    if event == 'start' and elem.tag == 'book':
        print(f"开始处理书: {elem.find('title').text}")
    elif event == 'end' and elem.tag == 'book':
        # 处理完成后清除元素,释放内存
        elem.clear()

# 只解析特定元素
context = ET.iterparse('large_file.xml', events=('end',))
for event, elem in context:
    if elem.tag == 'book' and event == 'end':
        # 只处理book元素
        process_book(elem)
        elem.clear()

四、常见错误与解决方法

错误情况原因解决方法
SyntaxErrorXML格式不正确检查XML是否完整,标签是否闭合
AttributeError元素不存在就访问属性先用if elem is not None:判断
中文乱码编码问题确保读写时指定encoding='utf-8'
找不到元素命名空间问题注册并使用命名空间前缀

五、快速参考表

任务方法示例
解析XMLET.parse()tree = ET.parse('file.xml')
获取根.getroot()root = tree.getroot()
查找单个.find()elem = root.find('path')
查找所有.findall()elems = root.findall('path')
遍历所有.iter()for el in root.iter('tag'):
获取文本.texttext = elem.text
获取属性.attribattr = elem.attrib
设置属性.set()elem.set('key', 'value')
创建元素ET.SubElement()child = ET.SubElement(parent, 'tag')