xml.etree.ElementTree — ElementTree XML API

源代码: 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

在本节中,我们将使用虚构的 country_data.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。 请查看文档以确保。

作为 Elementroot 有一个标签和一个属性字典

>>> 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 构造函数来访问文档类型声明。

用于非阻塞解析的 Pull 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 文档并且不想将其全部保存在内存中时,它会很有用。

如果需要通过事件获得*立即*反馈,调用 XMLPullParser.flush() 方法可以帮助减少延迟;请务必研究相关的安全说明。

查找感兴趣的元素

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.text)、添加和修改属性(Element.set() 方法)以及添加新子元素(例如使用 Element.append())来操作 Element 对象。

假设我们要为每个国家/地区的排名加一,并为排名元素添加一个 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'):
...     # using root.findall() to avoid removal during traversal
...     rank = int(country.find('rank').text)
...     if rank > 50:
...         root.remove(country)
...
>>> tree.write('output.xml')

请注意,迭代期间的并发修改会导致问题,就像迭代和修改 Python 列表或字典时一样。因此,该示例首先使用 root.findall() 收集所有匹配的元素,然后才迭代匹配项列表。

我们的 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>
</data>

构建 XML 文档

SubElement() 函数还提供了一种为给定元素创建新子元素的便捷方法

>>> a = ET.Element('a')
>>> b = ET.SubElement(a, 'b')
>>> c = ET.SubElement(a, 'c')
>>> d = ET.SubElement(c, 'd')
>>> ET.dump(a)
<a><b /><c><d /></c></a>

解析带有命名空间的 XML

如果 XML 输入具有 命名空间,则 prefix:sometag 形式的带前缀的标签和属性将扩展为 {uri}sometag,其中*前缀*被完整的*URI*替换。此外,如果存在 默认命名空间,则该完整 URI 将添加到所有无前缀标签的前面。

下面是一个 XML 示例,它包含两个命名空间,一个带有前缀“fictional”,另一个用作默认命名空间

<?xml version="1.0"?>
<actors xmlns:fictional="http://characters.example.com"
        xmlns="http://people.example.com">
    <actor>
        <name>John Cleese</name>
        <fictional:character>Lancelot</fictional:character>
        <fictional:character>Archie Leach</fictional:character>
    </actor>
    <actor>
        <name>Eric Idle</name>
        <fictional:character>Sir Robin</fictional:character>
        <fictional:character>Gunther</fictional:character>
        <fictional:character>Commander Clement</fictional:character>
    </actor>
</actors>

搜索和浏览此 XML 示例的一种方法是手动将 URI 添加到 find()findall() 的 xpath 中的每个标签或属性

root = fromstring(xml_text)
for actor in root.findall('{http://people.example.com}actor'):
    name = actor.find('{http://people.example.com}name')
    print(name.text)
    for char in actor.findall('{http://characters.example.com}character'):
        print(' |-->', char.text)

搜索命名空间 XML 示例的更好方法是使用您自己的前缀创建一个字典,并在搜索函数中使用这些前缀

ns = {'real_person': 'http://people.example.com',
      'role': 'http://characters.example.com'}

for actor in root.findall('real_person:actor', ns):
    name = actor.find('real_person:name', ns)
    print(name.text)
    for char in actor.findall('role:character', ns):
        print(' |-->', char.text)

这两种方法都输出

John Cleese
 |--> Lancelot
 |--> Archie Leach
Eric Idle
 |--> Sir Robin
 |--> Gunther
 |--> Commander Clement

XPath 支持

此模块为用于在树中定位元素的 XPath 表达式 提供了有限的支持。目标是支持简写语法的一小部分;完整的 XPath 引擎超出了模块的范围。

示例

下面是一个示例,演示了该模块的一些 XPath 功能。我们将使用 解析 XML 部分中的 countrydata XML 文档

import xml.etree.ElementTree as ET

root = ET.fromstring(countrydata)

# Top-level elements
root.findall(".")

# All 'neighbor' grand-children of 'country' children of the top-level
# elements
root.findall("./country/neighbor")

# Nodes with name='Singapore' that have a 'year' child
root.findall(".//year/..[@name='Singapore']")

# 'year' nodes that are children of nodes with name='Singapore'
root.findall(".//*[@name='Singapore']/year")

# All 'neighbor' nodes that are the second child of their parent
root.findall(".//neighbor[2]")

对于带有命名空间的 XML,请使用常用的限定 {namespace}tag 表示法

# All dublin-core "title" tags in the document
root.findall(".//{http://purl.org/dc/elements/1.1/}title")

支持的 XPath 语法

语法

含义

tag

选择具有给定标签的所有子元素。例如,spam 选择名为 spam 的所有子元素,而 spam/egg 选择名为 spam 的所有子元素中名为 egg 的所有孙元素。 {namespace}* 选择给定命名空间中的所有标签,{*}spam 选择任何(或无)命名空间中名为 spam 的标签,而 {}* 仅选择不在命名空间中的标签。

在 3.8 版更改: 添加了对星号通配符的支持。

*

选择所有子元素,包括注释和处理指令。例如,*/egg 选择名为 egg 的所有孙元素。

.

选择当前节点。这在路径的开头很有用,表示它是相对路径。

//

选择当前元素下方所有级别的所有子元素。例如,.//egg 选择整个树中的所有 egg 元素。

..

选择父元素。如果路径尝试到达开始元素(调用 find 的元素)的祖先,则返回 None

[@attrib]

选择具有给定属性的所有元素。

[@attrib='value']

选择给定属性具有给定值的所有元素。该值不能包含引号。

[@attrib!='value']

选择给定属性不具有给定值的所有元素。该值不能包含引号。

3.10 版后添加。

[tag]

选择具有名为 tag 的子元素的所有元素。仅支持直接子元素。

[.='text']

选择其完整文本内容(包括后代)等于给定 text 的所有元素。

3.7 版后添加。

[.!='text']

选择其完整文本内容(包括后代)不等于给定 text 的所有元素。

3.10 版后添加。

[tag='text']

选择具有名为 tag 的子元素的所有元素,其完整文本内容(包括后代)等于给定 text

[tag!='text']

选择所有子元素名为 tag 且完整文本内容(包括后代元素)不等于给定 text 的元素。

3.10 版后添加。

[位置]

选择位于给定位置的所有元素。位置可以是整数(1 表示第一个位置)、表达式 last()(表示最后一个位置)或相对于最后一个位置的位置(例如 last()-1)。

谓词(方括号内的表达式)前面必须是标签名称、星号或另一个谓词。position 谓词前面必须是标签名称。

参考

函数

xml.etree.ElementTree.canonicalize(xml_data=None, *, out=None, from_file=None, **options)

C14N 2.0 转换函数。

规范化是一种规范化 XML 输出的方式,它允许进行逐字节比较和数字签名。它减少了 XML 序列化程序的自由度,而是生成更受约束的 XML 表示形式。主要限制是关于命名空间声明的位置、属性的顺序和可忽略的空格。

此函数将 XML 数据字符串 (xml_data) 或文件路径或类文件对象 (from_file) 作为输入,将其转换为规范形式,并使用 out 文件(类)对象(如果提供)将其写出,或者如果未提供,则将其作为文本字符串返回。输出文件接收文本,而不是字节。因此,应在文本模式下以 utf-8 编码打开它。

典型用例

xml_data = "<root>...</root>"
print(canonicalize(xml_data))

with open("c14n_output.xml", mode='w', encoding='utf-8') as out_file:
    canonicalize(xml_data, out=out_file)

with open("c14n_output.xml", mode='w', encoding='utf-8') as out_file:
    canonicalize(from_file="inputfile.xml", out=out_file)

配置 options 如下

  • with_comments:设置为 true 以包含注释(默认值:false)

  • strip_text:设置为 true 以删除文本内容前后的空格

    (默认值:false)

  • rewrite_prefixes:设置为 true 以将命名空间前缀替换为“n{number}”

    (默认值:false)

  • qname_aware_tags:一组 qname 感知标签名称,其中应替换文本内容中的前缀

    (默认值:空)

  • qname_aware_attrs:一组 qname 感知属性名称,其中应替换前缀

    (默认值:空)

  • exclude_attrs:一组不应序列化的属性名称

  • exclude_tags:一组不应序列化的标签名称

在上面的选项列表中,“一组”指的是任何字符串集合或可迭代对象,不期望排序。

3.8 版新增。

xml.etree.ElementTree.Comment(text=None)

注释元素工厂。此工厂函数创建一个特殊元素,该元素将由标准序列化程序序列化为 XML 注释。注释字符串可以是字节串或 Unicode 字符串。text 是包含注释字符串的字符串。返回表示注释的元素实例。

请注意,XMLParser 会跳过输入中的注释,而不是为它们创建注释对象。ElementTree 仅在使用 Element 方法之一将注释节点插入到树中时才包含注释节点。

xml.etree.ElementTree.dump(elem)

将元素树或元素结构写入 sys.stdout。此函数仅应用于调试。

确切的输出格式取决于实现。在此版本中,它被写成一个普通的 XML 文件。

elem 是一个元素树或单个元素。

在 3.8 版更改: dump() 函数现在保留用户指定的属性顺序。

xml.etree.ElementTree.fromstring(text, parser=None)

从字符串常量解析 XML 部分。与 XML() 相同。text 是包含 XML 数据的字符串。parser 是可选的解析器实例。如果未给出,则使用标准 XMLParser 解析器。返回一个 Element 实例。

xml.etree.ElementTree.fromstringlist(sequence, parser=None)

从字符串片段序列解析 XML 文档。sequence 是包含 XML 数据片段的列表或其他序列。parser 是可选的解析器实例。如果未给出,则使用标准 XMLParser 解析器。返回一个 Element 实例。

3.2 版新增。

xml.etree.ElementTree.indent(tree, space='  ', level=0)

将空格附加到子树以直观地缩进树。这可用于生成格式良好的 XML 输出。tree 可以是 Element 或 ElementTree。space 是将为每个缩进级别插入的空格字符串,默认为两个空格字符。要缩进已缩进树中的部分子树,请将初始缩进级别作为 level 传递。

3.9 版新增。

xml.etree.ElementTree.iselement(element)

检查对象是否看起来是有效的元素对象。element 是一个元素实例。如果这是元素对象,则返回 True

xml.etree.ElementTree.iterparse(source, events=None, parser=None)

将 XML 片段增量解析为元素树,并向用户报告解析过程。source 是包含 XML 数据的文件名或 文件对象events 是要报告的事件序列。支持的事件是字符串 "start""end""comment""pi""start-ns""end-ns"(“ns” 事件用于获取详细的命名空间信息)。如果省略 events,则仅报告 "end" 事件。parser 是可选的解析器实例。如果未给出,则使用标准的 XMLParser 解析器。parser 必须是 XMLParser 的子类,并且只能使用默认的 TreeBuilder 作为目标。返回一个提供 (event, elem) 对的 迭代器;它有一个 root 属性,在完全读取 source 后,该属性引用生成的 XML 树的根元素。

请注意,虽然 iterparse() 会增量构建树,但它会在 source(或它命名的文件)上发出阻塞读取。因此,它不适用于无法进行阻塞读取的应用程序。有关完全非阻塞解析,请参阅 XMLPullParser

注意

iterparse() 仅保证在发出“start”事件时,它已经看到了开始标记的“>”字符,因此定义了属性,但在该时间点,text 和 tail 属性的内容是未定义的。这同样适用于元素子级;它们可能存在,也可能不存在。

如果需要完全填充的元素,请改用“end”事件。

自 3.4 版起弃用: parser 参数。

在 3.8 版更改: 添加了 commentpi 事件。

xml.etree.ElementTree.parse(source, parser=None)

将 XML 片段解析为元素树。source 是包含 XML 数据的文件名或文件对象。parser 是可选的解析器实例。如果未给出,则使用标准的 XMLParser 解析器。返回一个 ElementTree 实例。

xml.etree.ElementTree.ProcessingInstruction(target, text=None)

PI 元素工厂。此工厂函数创建一个特殊元素,该元素将被序列化为 XML 处理指令。target 是包含 PI 目标的字符串。text 是包含 PI 内容的字符串(如果给出)。返回一个表示处理指令的元素实例。

请注意,XMLParser 会跳过输入中的处理指令,而不是为它们创建 PI 对象。ElementTree 仅在使用 Element 方法之一将处理指令节点插入到树中时,才会包含处理指令节点。

xml.etree.ElementTree.register_namespace(prefix, uri)

注册命名空间前缀。注册表是全局的,对给定前缀或命名空间 URI 的任何现有映射都将被删除。prefix 是命名空间前缀。uri 是命名空间 URI。此命名空间中的标记和属性将尽可能使用给定的前缀进行序列化。

3.2 版新增。

xml.etree.ElementTree.SubElement(parent, tag, attrib={}, **extra)

子元素工厂。此函数创建一个元素实例,并将其附加到现有元素。

元素名称、属性名称和属性值可以是字节串或 Unicode 字符串。parent 是父元素。tag 是子元素名称。attrib 是一个可选字典,包含元素属性。extra 包含作为关键字参数给出的其他属性。返回一个元素实例。

xml.etree.ElementTree.tostring(element, encoding='us-ascii', method='xml', *, xml_declaration=None, default_namespace=None, short_empty_elements=True)

生成 XML 元素的字符串表示形式,包括所有子元素。element 是一个 Element 实例。encoding [1] 是输出编码(默认为 US-ASCII)。使用 encoding="unicode" 生成 Unicode 字符串(否则,将生成字节串)。method 可以是 "xml""html""text"(默认为 "xml")。xml_declarationdefault_namespaceshort_empty_elements 的含义与 ElementTree.write() 中的含义相同。返回一个(可选)包含 XML 数据的编码字符串。

在 3.4 版更改: 添加了 short_empty_elements 参数。

在 3.8 版更改: 添加了 xml_declarationdefault_namespace 参数。

在 3.8 版更改: tostring() 函数现在保留用户指定的属性顺序。

xml.etree.ElementTree.tostringlist(element, encoding='us-ascii', method='xml', *, xml_declaration=None, default_namespace=None, short_empty_elements=True)

生成 XML 元素的字符串表示形式,包括所有子元素。element 是一个 Element 实例。encoding [1] 是输出编码(默认为 US-ASCII)。使用 encoding="unicode" 生成 Unicode 字符串(否则,将生成字节串)。method 可以是 "xml""html""text"(默认为 "xml")。xml_declarationdefault_namespaceshort_empty_elements 的含义与 ElementTree.write() 中的含义相同。返回一个包含 XML 数据的(可选)编码字符串列表。它不保证任何特定的顺序,除了 b"".join(tostringlist(element)) == tostring(element)

3.2 版新增。

在 3.4 版更改: 添加了 short_empty_elements 参数。

在 3.8 版更改: 添加了 xml_declarationdefault_namespace 参数。

3.8 版后已更改: tostringlist() 函数现在保留用户指定的属性顺序。

xml.etree.ElementTree.XML(text, parser=None)

从字符串常量解析 XML 部分。此函数可用于在 Python 代码中嵌入“XML 字面量”。text 是一个包含 XML 数据的字符串。parser 是一个可选的解析器实例。如果未给出,则使用标准的 XMLParser 解析器。返回一个 Element 实例。

xml.etree.ElementTree.XMLID(text, parser=None)

从字符串常量解析 XML 部分,并返回一个字典,该字典从元素 ID 映射到元素。text 是一个包含 XML 数据的字符串。parser 是一个可选的解析器实例。如果未给出,则使用标准的 XMLParser 解析器。返回一个包含 Element 实例和字典的元组。

XInclude 支持

此模块通过 xml.etree.ElementInclude 帮助器模块为 XInclude 指令 提供有限的支持。此模块可用于根据树中的信息将子树和文本字符串插入到元素树中。

示例

以下示例演示了 XInclude 模块的使用。要在当前文档中包含 XML 文档,请使用 {http://www.w3.org/2001/XInclude}include 元素并将 parse 属性设置为 "xml",并使用 href 属性指定要包含的文档。

<?xml version="1.0"?>
<document xmlns:xi="http://www.w3.org/2001/XInclude">
  <xi:include href="source.xml" parse="xml" />
</document>

默认情况下,href 属性被视为文件名。您可以使用自定义加载器来覆盖此行为。另请注意,标准帮助器不支持 XPointer 语法。

要处理此文件,请像往常一样加载它,并将根元素传递给 xml.etree.ElementTree 模块

from xml.etree import ElementTree, ElementInclude

tree = ElementTree.parse("document.xml")
root = tree.getroot()

ElementInclude.include(root)

ElementInclude 模块将 {http://www.w3.org/2001/XInclude}include 元素替换为 source.xml 文档中的根元素。结果可能如下所示

<document xmlns:xi="http://www.w3.org/2001/XInclude">
  <para>This is a paragraph.</para>
</document>

如果省略 parse 属性,则默认为“xml”。href 属性是必需的。

要包含文本文档,请使用 {http://www.w3.org/2001/XInclude}include 元素,并将 parse 属性设置为“text”

<?xml version="1.0"?>
<document xmlns:xi="http://www.w3.org/2001/XInclude">
  Copyright (c) <xi:include href="year.txt" parse="text" />.
</document>

结果可能如下所示

<document xmlns:xi="http://www.w3.org/2001/XInclude">
  Copyright (c) 2003.
</document>

参考

函数

xml.etree.ElementInclude.default_loader(href, parse, encoding=None)

默认加载器。此默认加载器从磁盘读取包含的资源。href 是一个 URL。parse 是解析模式,可以是“xml”或“text”。encoding 是一个可选的文本编码。如果未给出,则编码为 utf-8。返回扩展的资源。如果解析模式为 "xml",则这是一个 Element 实例。如果解析模式为 "text",则这是一个字符串。如果加载器失败,它可以返回 None 或引发异常。

xml.etree.ElementInclude.include(elem, loader=None, base_url=None, max_depth=6)

此函数在 elem 指向的树中就地扩展 XInclude 指令。elem 是要查找此类元素的根 ElementElementTree 实例。loader 是一个可选的资源加载器。如果省略,则默认为 default_loader()。如果给出,它应该是一个可调用对象,其实现的接口与 default_loader() 相同。base_url 是原始文件的基 URL,用于解析相对包含文件引用。max_depth 是递归包含的最大数量。有限制以降低恶意内容爆炸的风险。传递 None 以禁用限制。

3.9 版后已更改: 添加了 base_urlmax_depth 参数。

元素对象

class xml.etree.ElementTree.Element(tag, attrib={}, **extra)

元素类。此类定义了元素接口,并提供了该接口的参考实现。

元素名称、属性名称和属性值可以是字节串或 Unicode 字符串。tag 是元素名称。attrib 是一个可选字典,包含元素属性。extra 包含作为关键字参数给出的附加属性。

tag

一个字符串,用于标识此元素表示的数据类型(换句话说,即元素类型)。

text
tail

这些属性可用于保存与元素关联的附加数据。它们的值通常是字符串,但也可以是任何特定于应用程序的对象。如果元素是从 XML 文件创建的,则 text 属性保存元素的开始标记与其第一个子元素或结束标记之间的文本,或 None,而 tail 属性保存元素的结束标记与下一个标记之间的文本,或 None。对于 XML 数据

<a><b>1<c>2<d/>3</c></b>4</a>

a 元素的 texttail 属性均为 Noneb 元素的 text"1"tail"4"c 元素的 text"2"tailNoned 元素的 textNonetail"3"

要收集元素的内部文本,请参阅 itertext(),例如 "".join(element.itertext())

应用程序可以在这些属性中存储任意对象。

attrib

包含元素属性的字典。请注意,虽然 attrib 值始终是一个真正的可变 Python 字典,但 ElementTree 实现可以选择使用另一种内部表示形式,并且仅在有人请求时才创建字典。要利用此类实现,请尽可能使用下面的字典方法。

以下类似字典的方法适用于元素属性。

clear()

重置元素。此函数将删除所有子元素,清除所有属性,并将 text 和 tail 属性设置为 None

get(key, default=None)

获取名为 key 的元素属性。

返回属性值,如果未找到该属性,则返回 default

items()

以 (名称, 值) 对的序列形式返回元素属性。属性以任意顺序返回。

keys()

以列表形式返回元素属性名称。名称以任意顺序返回。

set(key, value)

将元素上的属性 key 设置为 value

以下方法适用于元素的子元素。

append(subelement)

将元素 subelement 添加到此元素的内部子元素列表的末尾。如果 subelement 不是 Element,则引发 TypeError

extend(subelements)

从包含零个或多个元素的序列对象追加 subelements。如果子元素不是 Element,则引发 TypeError

3.2 版新增。

find(match, namespaces=None)

查找与 match 匹配的第一个子元素。match 可以是标记名称或 路径。返回一个元素实例或 Nonenamespaces 是一个可选映射,用于将命名空间前缀映射到完整名称。传递 '' 作为前缀,将表达式中所有无前缀的标记名称移动到给定的命名空间中。

findall(match, namespaces=None)

按标记名称或 路径 查找所有匹配的子元素。返回一个列表,其中包含按文档顺序排列的所有匹配元素。namespaces 是一个可选映射,用于将命名空间前缀映射到完整名称。传递 '' 作为前缀,将表达式中所有无前缀的标记名称移动到给定的命名空间中。

findtext(match, default=None, namespaces=None)

查找与 match 匹配的第一个子元素的文本。match 可以是标记名称或 路径。返回第一个匹配元素的文本内容,如果未找到元素,则返回 default。请注意,如果匹配的元素没有文本内容,则返回空字符串。namespaces 是一个可选映射,用于将命名空间前缀映射到完整名称。传递 '' 作为前缀,将表达式中所有无前缀的标记名称移动到给定的命名空间中。

insert(index, subelement)

在该元素的指定位置插入 subelement。如果 subelement 不是 Element,则引发 TypeError

iter(tag=None)

创建一个以当前元素为根的树 迭代器。迭代器按文档顺序(深度优先)迭代此元素及其下的所有元素。如果 tag 不是 None'*',则迭代器仅返回标签等于 tag 的元素。如果在迭代过程中修改了树结构,则结果未定义。

3.2 版新增。

iterfind(match, namespaces=None)

按标签名称或 路径 查找所有匹配的子元素。返回一个可迭代对象,该对象按文档顺序生成所有匹配的元素。namespaces 是一个可选映射,用于将命名空间前缀映射到完整名称。

3.2 版新增。

itertext()

创建一个文本迭代器。迭代器按文档顺序循环遍历此元素和所有子元素,并返回所有内部文本。

3.2 版新增。

makeelement(tag, attrib)

创建一个与该元素类型相同的新元素对象。不要调用此方法,请改用 SubElement() 工厂函数。

remove(subelement)

从元素中移除 subelement。与 find* 方法不同,此方法根据实例标识比较元素,而不是根据标签值或内容比较。

Element 对象还支持以下序列类型方法来处理子元素:__delitem__()__getitem__()__setitem__()__len__()

注意:没有子元素的元素将测试为 False。测试元素的真值已被弃用,并将在 Python 3.14 中引发异常。请改用特定的 len(elem)elem is None 测试。

element = root.find('foo')

if not element:  # careful!
    print("element not found, or element has no subelements")

if element is None:
    print("element not found")

在 3.12 版更改: 测试元素的真值会发出 DeprecationWarning

在 Python 3.8 之前,元素的 XML 属性的序列化顺序是通过按名称对属性进行排序来人为地使其可预测的。基于现在保证的字典顺序,在 Python 3.8 中删除了这种任意的重新排序,以保留最初解析属性或用户代码创建属性的顺序。

一般来说,用户代码应尽量不要依赖于属性的特定顺序,因为 XML 信息集 明确地排除了属性顺序来传递信息。代码应该准备好处理输入的任何顺序。如果需要确定性的 XML 输出,例如用于加密签名或测试数据集,则可以使用 canonicalize() 函数进行规范序列化。

如果规范输出不适用,但仍然需要特定的属性顺序输出,则代码应旨在直接按所需顺序创建属性,以避免代码阅读器产生感知上的不匹配。如果这很难实现,则可以在序列化之前应用如下配方来强制执行独立于元素创建的顺序

def reorder_attributes(root):
    for el in root.iter():
        attrib = el.attrib
        if len(attrib) > 1:
            # adjust attribute order, e.g. by sorting
            attribs = sorted(attrib.items())
            attrib.clear()
            attrib.update(attribs)

ElementTree 对象

class xml.etree.ElementTree.ElementTree(element=None, file=None)

ElementTree 包装器类。此类表示整个元素层次结构,并为与标准 XML 之间的序列化添加了一些额外的支持。

element 是根元素。如果给定,则使用 XML file 的内容初始化树。

_setroot(element)

替换此树的根元素。这将丢弃树的当前内容,并将其替换为给定元素。谨慎使用。element 是一个元素实例。

find(match, namespaces=None)

Element.find() 相同,从树的根开始。

findall(match, namespaces=None)

Element.findall() 相同,从树的根开始。

findtext(match, default=None, namespaces=None)

Element.findtext() 相同,从树的根开始。

getroot()

返回此树的根元素。

iter(tag=None)

为根元素创建并返回一个树迭代器。迭代器按顺序循环遍历此树中的所有元素。tag 是要查找的标签(默认返回所有元素)。

iterfind(match, namespaces=None)

Element.iterfind() 相同,从树的根开始。

3.2 版新增。

parse(source, parser=None)

将外部 XML 片段加载到此元素树中。source 是文件名或 文件对象parser 是可选的解析器实例。如果未给出,则使用标准 XMLParser 解析器。返回片段根元素。

write(file, encoding='us-ascii', xml_declaration=None, default_namespace=None, method='xml', *, short_empty_elements=True)

将元素树写入文件,格式为 XML。file 是文件名,或者是以写入模式打开的 文件对象encoding [1] 是输出编码(默认为 US-ASCII)。xml_declaration 控制是否应在文件中添加 XML 声明。使用 False 表示从不添加,True 表示始终添加,None 表示仅当编码不是 US-ASCII、UTF-8 或 Unicode 时添加(默认为 None)。default_namespace 设置默认 XML 命名空间(用于“xmlns”)。method 可以是 "xml""html""text"(默认为 "xml")。仅限关键字参数 short_empty_elements 控制不包含内容的元素的格式。如果为 True(默认值),则将它们作为单个自闭合标签发出,否则将它们作为一对开始/结束标签发出。

输出可以是字符串 (str) 或二进制 (bytes)。这由 encoding 参数控制。如果 encoding"unicode",则输出为字符串;否则为二进制。请注意,如果 file 是打开的 文件对象,这可能会与其类型冲突;请确保不要尝试将字符串写入二进制流,反之亦然。

在 3.4 版更改: 添加了 short_empty_elements 参数。

版本 3.8 中的变化: write() 方法现在保留用户指定的属性顺序。

这是将要被操作的 XML 文件

<html>
    <head>
        <title>Example page</title>
    </head>
    <body>
        <p>Moved to <a href="http://example.org/">example.org</a>
        or <a href="http://example.com/">example.com</a>.</p>
    </body>
</html>

更改第一段中每个链接的“target”属性的示例

>>> from xml.etree.ElementTree import ElementTree
>>> tree = ElementTree()
>>> tree.parse("index.xhtml")
<Element 'html' at 0xb77e6fac>
>>> p = tree.find("body/p")     # Finds first occurrence of tag p in body
>>> p
<Element 'p' at 0xb77ec26c>
>>> links = list(p.iter("a"))   # Returns list of all links
>>> links
[<Element 'a' at 0xb77ec2ac>, <Element 'a' at 0xb77ec1cc>]
>>> for i in links:             # Iterates through all found links
...     i.attrib["target"] = "blank"
...
>>> tree.write("output.xhtml")

QName 对象

class xml.etree.ElementTree.QName(text_or_uri, tag=None)

QName 包装器。这可以用来包装 QName 属性值,以便在输出时获得正确的命名空间处理。text_or_uri 是一个包含 QName 值的字符串,格式为 {uri}local,或者,如果给出了 tag 参数,则为 QName 的 URI 部分。如果给出了 tag,则第一个参数被解释为 URI,而此参数被解释为本地名称。QName 实例是不透明的。

TreeBuilder 对象

class xml.etree.ElementTree.TreeBuilder(element_factory=None, *, comment_factory=None, pi_factory=None, insert_comments=False, insert_pis=False)

通用元素结构构建器。此构建器将一系列 start、data、end、comment 和 pi 方法调用转换为格式良好的元素结构。您可以使用此类使用自定义 XML 解析器或其他类似 XML 格式的解析器来构建元素结构。

element_factory 如果给出,则必须是接受两个位置参数的可调用对象:标签和属性字典。它应该返回一个新的元素实例。

comment_factorypi_factory 函数(如果给出)的行为应类似于 Comment()ProcessingInstruction() 函数,用于创建注释和处理指令。如果未给出,则将使用默认工厂。当 insert_comments 和/或 insert_pis 为 true 时,如果注释/pi 出现在根元素内(但不在其外部),则会将它们插入到树中。

close()

刷新构建器缓冲区,并返回顶级文档元素。返回一个 Element 实例。

data(data)

向当前元素添加文本。data 是一个字符串。它应该是字节串或 Unicode 字符串。

end(tag)

关闭当前元素。tag 是元素名称。返回已关闭的元素。

start(tag, attrs)

打开一个新元素。tag 是元素名称。attrs 是一个包含元素属性的字典。返回已打开的元素。

comment(text)

使用给定的 *text* 创建注释。如果 insert_comments 为真,这也会将其添加到树中。

3.8 版新增。

pi(target, text)

使用给定的 *target* 名称和 *text* 创建处理指令。如果 insert_pis 为真,这也会将其添加到树中。

3.8 版新增。

此外,自定义 TreeBuilder 对象可以提供以下方法

doctype(name, pubid, system)

处理 doctype 声明。*name* 是 doctype 名称。*pubid* 是公共标识符。*system* 是系统标识符。此方法在默认的 TreeBuilder 类中不存在。

3.2 版新增。

start_ns(prefix, uri)

每当解析器遇到新的命名空间声明时,在定义它的开始元素的 start() 回调之前调用。对于默认命名空间,*prefix* 为 '',否则为声明的命名空间前缀名称。*uri* 是命名空间 URI。

3.8 版新增。

end_ns(prefix)

在声明命名空间前缀映射的元素的 end() 回调之后调用,并带有超出范围的 *prefix* 名称。

3.8 版新增。

class xml.etree.ElementTree.C14NWriterTarget(write, *, with_comments=False, strip_text=False, rewrite_prefixes=False, qname_aware_tags=None, qname_aware_attrs=None, exclude_attrs=None, exclude_tags=None)

一个 C14N 2.0 写入器。参数与 canonicalize() 函数相同。此类不构建树,而是使用 *write* 函数将回调事件直接转换为序列化形式。

3.8 版新增。

XMLParser 对象

class xml.etree.ElementTree.XMLParser(*, target=None, encoding=None)

此类是模块的底层构建块。它使用 xml.parsers.expat 对 XML 进行高效的、基于事件的解析。可以使用 feed() 方法增量地向其提供 XML 数据,并且解析事件通过在 *target* 对象上调用回调来转换为推送 API。如果省略 *target*,则使用标准的 TreeBuilder。如果给出了 *encoding* [1],则该值将覆盖 XML 文件中指定的编码。

在 3.8 版更改: 参数现在是 仅限关键字。不再支持 *html* 参数。

close()

完成向解析器提供数据。返回在构造期间调用传递的 *target* 的 close() 方法的结果;默认情况下,这是顶级文档元素。

feed(data)

向解析器提供数据。*data* 是编码后的数据。

flush()

触发解析任何先前提供的未解析数据,这可用于确保更即时的反馈,特别是在 Expat >=2.6.0 中。 flush() 的实现会暂时禁用 Expat 中的重新解析延迟(如果当前已启用)并触发重新解析。禁用重新解析延迟会带来安全隐患;有关详细信息,请参阅 xml.parsers.expat.xmlparser.SetReparseDeferralEnabled()

请注意,flush() 已被反向移植到 CPython 的一些先前版本中,作为安全修复程序。如果在各种 Python 版本中运行的代码中使用,请使用 hasattr() 检查 flush() 的可用性。

3.12.3 版新增。

XMLParser.feed() 会为每个开始标签调用 *target* 的 start(tag, attrs_dict) 方法,为每个结束标签调用其 end(tag) 方法,并通过方法 data(data) 处理数据。有关更多受支持的回调方法,请参阅 TreeBuilder 类。 XMLParser.close() 会调用 *target* 的方法 close()XMLParser 不仅可以用于构建树结构。以下是计算 XML 文件最大深度的示例

>>> from xml.etree.ElementTree import XMLParser
>>> class MaxDepth:                     # The target object of the parser
...     maxDepth = 0
...     depth = 0
...     def start(self, tag, attrib):   # Called for each opening tag.
...         self.depth += 1
...         if self.depth > self.maxDepth:
...             self.maxDepth = self.depth
...     def end(self, tag):             # Called for each closing tag.
...         self.depth -= 1
...     def data(self, data):
...         pass            # We do not need to do anything with data.
...     def close(self):    # Called when all data has been parsed.
...         return self.maxDepth
...
>>> target = MaxDepth()
>>> parser = XMLParser(target=target)
>>> exampleXml = """
... <a>
...   <b>
...   </b>
...   <b>
...     <c>
...       <d>
...       </d>
...     </c>
...   </b>
... </a>"""
>>> parser.feed(exampleXml)
>>> parser.close()
4

XMLPullParser 对象

class xml.etree.ElementTree.XMLPullParser(events=None)

适用于非阻塞应用程序的拉式解析器。其输入端 API 类似于 XMLParser,但 XMLPullParser 不是将调用推送到回调目标,而是收集解析事件的内部列表并让用户从中读取。*events* 是要报告的事件序列。支持的事件是字符串 "start""end""comment""pi""start-ns""end-ns"(“ns”事件用于获取详细的命名空间信息)。如果省略 *events*,则仅报告 "end" 事件。

feed(data)

将给定的字节数据提供给解析器。

flush()

触发对任何先前已提供但未解析的数据的解析,这可用于确保更即时的反馈,尤其是在 Expat >=2.6.0 中。 flush() 的实现会暂时禁用 Expat 的重新解析延迟(如果当前已启用)并触发重新解析。禁用重新解析延迟会带来安全隐患;有关详细信息,请参阅 xml.parsers.expat.xmlparser.SetReparseDeferralEnabled()

请注意,flush() 已被反向移植到 CPython 的一些先前版本中,作为安全修复程序。如果在跨多个 Python 版本运行的代码中使用,请使用 hasattr() 检查 flush() 的可用性。

3.12.3 版新增。

close()

向解析器发出数据流已终止的信号。与 XMLParser.close() 不同,此方法始终返回 None。关闭解析器时尚未检索到的任何事件仍然可以使用 read_events() 读取。

read_events()

返回一个迭代器,该迭代器迭代已在提供给解析器的数据中遇到的事件。迭代器生成 (event, elem) 对,其中 *event* 是表示事件类型的字符串(例如 "end"),而 *elem* 是遇到的 Element 对象,或其他上下文值,如下所示。

  • startend:当前元素。

  • commentpi:当前注释/处理指令

  • start-ns:命名已声明的命名空间映射的元组 (prefix, uri)

  • end-nsNone(这在未来版本中可能会更改)

先前调用 read_events() 时提供的事件将不再生成。仅当从迭代器中检索事件时,才会从内部队列中消耗事件,因此多个读取器并行迭代从 read_events() 获取的迭代器将产生不可预测的结果。

注意

XMLPullParser 仅保证在发出“start”事件时已看到开始标记的“>”字符,因此已定义属性,但在该时间点,text 和 tail 属性的内容未定义。这同样适用于元素子级;它们可能存在,也可能不存在。

如果需要完全填充的元素,请改用“end”事件。

3.4 版新增。

在 3.8 版更改: 添加了 commentpi 事件。

异常

class xml.etree.ElementTree.ParseError

XML 解析错误,由该模块中的各种解析方法在解析失败时引发。此异常实例的字符串表示形式将包含用户友好的错误消息。此外,它还将具有以下可用属性

code

来自 expat 解析器的数字错误代码。有关错误代码列表及其含义,请参阅 xml.parsers.expat 的文档。

position

一个由 *line*、*column* 数字组成的元组,指定发生错误的位置。

脚注