xml.etree.ElementTree(简称ElementTree)是Python标准库中用于处理XML文件的模块。它提供了简洁且高效的API,适用于解析、创建和修改XML文档。在需要处理XML数据的场景中,比如配置文件、数据交换格式、Web服务响应等,ElementTree都是非常实用的工具。
一、基本使用场景
- 解析XML文档:读取并解析XML文档,将其转换为树结构以便进一步操作。
- 创建XML文档:从头开始构建XML文档,并将其保存到文件中。
- 修改XML文档:在解析后的XML树中添加、删除或修改元素。
- 搜索与遍历XML树:查找特定的元素或属性,遍历整个XML树结构。
二、核心API与用法
1. 解析XML文档
解析字符串形式的XML:
1
2
3
4
5
6
7
8
9
10
11
|
import xml.etree.ElementTree as ET
xml_data = '''<data>
<user>
<name>John</name>
<age>30</age>
</user>
</data>'''
root = ET.fromstring(xml_data)
print(root.tag)
|
输出:
data
解析XML文件:
1
2
3
4
5
|
import xml.etree.ElementTree as ET
tree = ET.parse('example.xml')
root = tree.getroot()
print(root.tag)
|
输出:
data
2. 创建XML文档
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
import xml.etree.ElementTree as ET
# 创建根元素
root = ET.Element('data')
# 创建子元素
user = ET.SubElement(root, 'user')
name = ET.SubElement(user, 'name')
name.text = 'John'
age = ET.SubElement(user, 'age')
age.text = '30'
# 将XML树写入文件
tree = ET.ElementTree(root)
tree.write('output.xml', encoding='utf-8', xml_declaration=True)
|
生成的output.xml内容:
1
2
3
4
5
6
7
|
<?xml version='1.0' encoding='utf-8'?>
<data>
<user>
<name>John</name>
<age>30</age>
</user>
</data>
|
3. 修改XML文档
修改现有元素的文本内容:
1
2
3
4
5
6
7
8
9
|
import xml.etree.ElementTree as ET
tree = ET.parse('output.xml')
root = tree.getroot()
# 修改元素内容
root.find('user/name').text = 'Jane'
tree.write('output_modified.xml', encoding='utf-8', xml_declaration=True)
|
output_modified.xml内容:
1
2
3
4
5
6
7
|
<?xml version='1.0' encoding='utf-8'?>
<data>
<user>
<name>Jane</name>
<age>30</age>
</user>
</data>
|
4. 搜索与遍历XML树
遍历所有子元素:
1
2
3
4
5
6
7
|
import xml.etree.ElementTree as ET
tree = ET.parse('output.xml')
root = tree.getroot()
for child in root.iter():
print(child.tag, child.text)
|
输出:
data None
user None
name John
age 30
查找特定元素:
1
2
3
4
5
6
7
|
import xml.etree.ElementTree as ET
tree = ET.parse('output.xml')
root = tree.getroot()
name = root.find('user/name')
print(name.text)
|
输出:
John
三、进阶用法
1. 处理带有命名空间的XML
命名空间在复杂XML文档中非常常见,用于区分不同元素的作用域。
解析带有命名空间的XML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
import xml.etree.ElementTree as ET
xml_data = '''<root xmlns:h="http://www.w3.org/TR/html4/" xmlns:f="http://www.w3schools.com/furniture">
<h:table>
<h:tr>
<h:td>Apples</h:td>
<h:td>Bananas</h:td>
</h:tr>
</h:table>
<f:table>
<f:name>African Coffee Table</f:name>
<f:width>80</f:width>
<f:length>120</f:length>
</f:table>
</root>'''
root = ET.fromstring(xml_data)
# 使用命名空间解析
for table in root.findall('{http://www.w3.org/TR/html4/}table'):
for td in table.findall('{http://www.w3.org/TR/html4/}td'):
print(td.text)
|
输出:
Apples
Bananas
2. 使用XPath查找元素
虽然ElementTree本身不支持完整的XPath语法,但提供了类似的路径查找功能。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
import xml.etree.ElementTree as ET
xml_data = '''<root>
<users>
<user id="1">
<name>John</name>
</user>
<user id="2">
<name>Jane</name>
</user>
</users>
</root>'''
root = ET.fromstring(xml_data)
# 查找id为2的用户的名称
name = root.find('.//user[@id="2"]/name').text
print(name)
|
输出:
Jane
3. 批量处理和转换XML
当需要处理大量的XML数据时,可以利用生成器或者批量处理方法来提高效率。
1
2
3
4
5
6
7
8
9
10
11
|
import xml.etree.ElementTree as ET
def parse_large_xml(file):
context = ET.iterparse(file, events=('start', 'end'))
for event, elem in context:
if event == 'end' and elem.tag == 'user':
yield elem
elem.clear() # 清除元素以节省内存
for user in parse_large_xml('large_users.xml'):
print(user.find('name').text)
|
四、常用技巧
1. 使用生成器高效解析大文件
如上所述,使用iterparse()和生成器可以有效节省内存并提高处理速度,适用于大文件的解析。
2. 自动缩进与格式化输出
默认情况下,ElementTree生成的XML是无缩进的,可以通过手动调整生成XML的格式来使其更具可读性。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
import xml.etree.ElementTree as ET
def indent(elem, level=0):
i = "\n" + level*" "
if len(elem):
if not elem.text or not elem.text.strip():
elem.text = i + " "
if not elem.tail or not elem.tail.strip():
elem.tail = i
for subelem in elem:
indent(subelem, level+1)
if not elem.tail or not elem.tail.strip():
elem.tail = i
else:
if level and (not elem.tail or not elem.tail.strip()):
elem.tail = i
root = ET.Element("root")
child = ET.SubElement(root, "child")
indent(root)
tree = ET.ElementTree(root)
tree.write("output_pretty.xml", encoding="utf-8", xml_declaration=True)
|
生成的output_pretty.xml内容:
1
2
3
4
|
<?xml version='1.0' encoding='utf-8'?>
<root>
<child />
</root>
|
3. 安全处理外部实体
在处理来自不受信任源的XML数据时,最好禁用外部实体,以防止XML外部实体注入(XXE)攻击。
1
2
3
4
5
6
7
8
9
|
import xml.etree.ElementTree as ET
from defusedxml.ElementTree import parse, fromstring
# 安全地解析XML
tree = parse('example.xml')
root = tree.getroot()
# 或者
root = fromstring(xml_data)
|
defusedxml库提供了更安全的XML解析方法,防止常见的安全漏洞。
|