源代码: Lib/xml/etree/ElementTree.py
xml.etree.ElementTree 模块实现了一个简单高效的API,用于解析和创建XML数据。
在 3.3 版更改: 此模块将在可能的情况下使用快速实现。
3.3 版后已移除: xml.etree.cElementTree
模块已被弃用。
警告
xml.etree.ElementTree 模块对于恶意构建的数据是不安全的。如果需要解析不可信或未经身份验证的数据,请参见 XML 漏洞 。
教程
这是一个使用 xml.etree.ElementTree (简称 ET
)的简短教程。目标是演示模块的一些构建块和基本概念。
XML 树和元素
XML 是一种继承性的分层数据格式,最自然的表示方法是使用树。 为此, ET
有两个类 -- ElementTree 将整个XML文档表示为一个树, Element 表示该树中的单个节点。 与整个文档的交互(读写文件)通常在 ElementTree 级别完成。 与单个 XML 元素及其子元素的交互是在 Element 级别完成的。
解析 XML
我们将使用以下 XML 文档作为本节的示例数据:
<?xml version="1.0"?> <data> <country name="Liechtenstein"> <rank>1</rank> <year>2008</year> <gdppc>141100</gdppc> <neighbor name="Austria" direction="E"/> <neighbor name="Switzerland" direction="W"/> </country> <country name="Singapore"> <rank>4</rank> <year>2011</year> <gdppc>59900</gdppc> <neighbor name="Malaysia" direction="N"/> </country> <country name="Panama"> <rank>68</rank> <year>2011</year> <gdppc>13600</gdppc> <neighbor name="Costa Rica" direction="W"/> <neighbor name="Colombia" direction="E"/> </country> </data>
可以通过从文件中读取来导入此数据:
import xml.etree.ElementTree as ET tree = ET.parse('country_data.xml') root = tree.getroot()
或直接从字符串中解析:
root = ET.fromstring(country_data_as_string)
fromstring() 将 XML 从字符串直接解析为 Element ,该元素是已解析树的根元素。 其他解析函数可能会创建一个 ElementTree 。 确切信息请查阅文档。
作为 Element , root
具有标签和属性字典:
>>>
>>> root.tag 'data' >>> root.attrib {}
还有可以迭代的子节点:
>>>
>>> for child in root: ... print(child.tag, child.attrib) ... country {'name': 'Liechtenstein'} country {'name': 'Singapore'} country {'name': 'Panama'}
子级是可以嵌套的,我们可以通过索引访问特定的子级节点:
>>>
>>> root[0][1].text '2008'
备注
并非 XML 输入的所有元素都将作为解析树的元素结束。 目前,此模块跳过输入中的任何 XML 注释、处理指令和文档类型声明。 然而,使用这个模块的 API 而不是从 XML 文本解析构建的树可以包含注释和处理指令,生成 XML 输出时同样包含这些注释和处理指令。 可以通过将自定义 TreeBuilder 实例传递给 XMLParser 构造器来访问文档类型声明。
用于非阻塞解析的拉取 API
此模块所提供了大多数解析函数都要求在返回任何结果之前一次性读取整个文档。 可以使用 XMLParser 并以增量方式添加数据,但这是在回调目标上调用方法的推送式 API。 有时用户真正想要的是能够以增量方式解析 XML 而无需阻塞操作,同时享受完整的已构造 Element 对象。
针对此需求的最强大工具是 XMLPullParser。 它不要求通过阻塞式读取来获得 XML 数据,而是通过执行 XMLPullParser.feed() 调用来增量式地添加数据。 要获得已解析的 XML 元素,应调用 XMLPullParser.read_events()。 下面是一个示例:
>>>
>>> parser = ET.XMLPullParser(['start', 'end']) >>> parser.feed('<mytag>sometext') >>> list(parser.read_events()) [('start', <Element 'mytag' at 0x7fa66db2be58>)] >>> parser.feed(' more text</mytag>') >>> for event, elem in parser.read_events(): ... print(event) ... print(elem.tag, 'text=', elem.text) ... end mytag text= sometext more text
常见的用例是针对以非阻塞方式进行的应用程序,其中 XML 是从套接字接收或从某些存储设备增量式读取的。 在这些用例中,阻塞式读取是不可接受的。
因为其非常灵活,XMLPullParser 在更简单的用例中使用起来可能并不方便。 如果你不介意你的应用程序在读取 XML 数据时造成阻塞但仍希望具有增量解析能力,可以考虑 iterparse()。 它在你读取大型 XML 文档并且不希望将它完全放去内存时会很适用。
查找感兴趣的元素
Element 有一些很有效的方法,可帮助递归遍历其下的所有子树(包括子级,子级的子级,等等)。例如 Element.iter():
>>>
>>> for neighbor in root.iter('neighbor'): ... print(neighbor.attrib) ... {'name': 'Austria', 'direction': 'E'} {'name': 'Switzerland', 'direction': 'W'} {'name': 'Malaysia', 'direction': 'N'} {'name': 'Costa Rica', 'direction': 'W'} {'name': 'Colombia', 'direction': 'E'}
Element.findall() 仅查找当前元素的直接子元素中带有指定标签的元素。 Element.find() 找带有特定标签的 第一个 子级,然后可以用 Element.text 访问元素的文本内容。 Element.get 访问元素的属性:
>>>
>>> for country in root.findall('country'): ... rank = country.find('rank').text ... name = country.get('name') ... print(name, rank) ... Liechtenstein 1 Singapore 4 Panama 68
通过使用 XPath ,可以更精确地指定要查找的元素。
修改XML文件
ElementTree 提供了一种构建XML文档并将其写入文件的简单方法。调用 ElementTree.write() 方法就可以实现。
创建后可以直接操作 Element 对象。例如:使用 Element.text 修改文本字段,使用 Element.set() 方法添加和修改属性,以及使用 Element.append() 添加新的子元素。
假设我们要为每个国家/地区的中添加一个排名,并在排名元素中添加一个 updated
属性:
>>>
>>> for rank in root.iter('rank'): ... new_rank = int(rank.text) + 1 ... rank.text = str(new_rank) ... rank.set('updated', 'yes') ... >>> tree.write('output.xml')
生成的XML现在看起来像这样:
<?xml version="1.0"?> <data> <country name="Liechtenstein"> <rank updated="yes">2</rank> <year>2008</year> <gdppc>141100</gdppc> <neighbor name="Austria" direction="E"/> <neighbor name="Switzerland" direction="W"/> </country> <country name="Singapore"> <rank updated="yes">5</rank> <year>2011</year> <gdppc>59900</gdppc> <neighbor name="Malaysia" direction="N"/> </country> <country name="Panama"> <rank updated="yes">69</rank> <year>2011</year> <gdppc>13600</gdppc> <neighbor name="Costa Rica" direction="W"/> <neighbor name="Colombia" direction="E"/> </country> </data>
可以使用 Element.remove() 删除元素。假设我们要删除排名高于50的所有国家/地区:
>>>
>>> for country in root.findall('country'): ...