20.5. "xml.etree.ElementTree" ---  ElementTree XML API
******************************************************

**源代码：** Lib/xml/etree/ElementTree.py

======================================================================

"xml.etree.ElementTree" 模块实现了一个简单高效的API，用于解析和创建XML
数据。

在 3.3 版更改: 只要有可能，这个模块将使用快速实现。
"xml.etree.cElementTree" 模块已弃用。

警告:

  "xml.etree.ElementTree" 模块对于恶意构建的数据是不安全的。如果需要解
  析不可信或未经身份验证的数据，请参见 XML 漏洞 。


20.5.1. 教程
============

这是一个使用 "xml.etree.ElementTree" （简称 "ET" ）的简短教程。目标是
演示模块的一些构建块和基本概念。


20.5.1.1. XML树和元素
---------------------

XML是一种固有的分层数据格式，最自然的表示方法是使用树。为此， "ET" 有
两个类 "ElementTree" 将整个XML文档表示为一个树， "Element" 表示该树中
的单个节点。与整个文档的交互（读写文件）通常在 "ElementTree" 级别完成
。与单个XML元素及其子元素的交互是在 "Element" 级别完成的。


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


20.5.1.3. 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

常见的用例是针对以非阻塞方式进行的应用程序，其中 XML 是从套接字接收或
从某些存储设备渐进式读取的。 在这些用例中，阻塞式读取是不可接受的。

因为其非常灵活，"XMLPullParser" 在更简单的用例中使用起来可能并不方便。
如果你不介意你的应用程序在读取 XML 数据时造成阻塞但仍希望具有增量解析
能力，可以考虑 "iterparse()"。 它在你读取大型 XML 文档并且不希望将它完
全放去内存时会很适用。


20.5.1.4. 寻找有趣的元素
------------------------

"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.text" 访问元素的属性:

   >>> 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 ，可以更精确地指定要查找的元素。


20.5.1.5. 修改XML文件
---------------------

"ElementTree" 提供了一种构建XML文档并将其写入文件的简单方法。
"ElementTree.write()" 方法可达到此目的。

创建后可以直接操作 "Element" 对象。例如：使用 "Element.text" 修改文本
字段，使用 "Element.set()" 方法添加和修改属性，以及使用
"Element.append()" 添加新的子元素。

假设我们要在每个国家/地区的中添加一个排名，并在rank元素中添加一个
"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'):
   ...     rank = int(country.find('rank').text)
   ...     if rank > 50:
   ...         root.remove(country)
   ...
   >>> 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>
   </data>


20.5.1.6. 构建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>


20.5.1.7. 使用命名空间解析XML
-----------------------------

如果 XML 输入带有 命名空间，则具有前缀的 "prefix:sometag" 形式的标记和
属性将被扩展为 "{uri}sometag"，其中 *prefix* 会被完整 *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 示例的一种方式是手动为 "find()" 或 "findall()" 的
xpath 中的每个标记或属性添加 URI:

   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


20.5.1.8. 其他资源
------------------

请访问 http://effbot.org/zone/element-index.htm 获取教程和其他文档的链
接。


20.5.2. XPath支持
=================

此模块提供了对 XPath 表达式 的有限支持用于在树中定位元素。 其目标是支
持一个简化语法的较小子集；完整的 XPath 引擎超出了此模块的适用范围。


20.5.2.1. 示例
--------------

下面是一个演示此模块的部分 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]")


20.5.2.2. 支持的XPath语法
-------------------------

+-------------------------+--------------------------------------------------------+
| 语法                    | 含义                                                   |
|=========================|========================================================|
| "tag"                   | Selects all child elements with the given tag. For     |
|                         | example, "spam" selects all child elements named       |
|                         | "spam", and "spam/egg" selects all grandchildren named |
|                         | "egg" in all children named "spam".                    |
+-------------------------+--------------------------------------------------------+
| "*"                     | Selects all child elements.  For example, "*/egg"      |
|                         | selects all grandchildren named "egg".                 |
+-------------------------+--------------------------------------------------------+
| "."                     | 选择当前节点。这在路径的开头非常有用，用于指示它是相对 |
|                         | 路径。                                                 |
+-------------------------+--------------------------------------------------------+
| "//"                    | 选择所有子元素 在当前元素的所有下级中选择所有下级元素  |
|                         | 。 例如，".//egg" 是在整个树中选择所有 "egg" 元素。    |
+-------------------------+--------------------------------------------------------+
| ".."                    | 选择父元素。 如果路径试图前往起始元素的上级（元素的    |
|                         | "find" 被调用）则 返回 "None"。                        |
+-------------------------+--------------------------------------------------------+
| "[@attrib]"             | 选择具有给定属性的所有元素。                           |
+-------------------------+--------------------------------------------------------+
| "[@attrib='value']"     | 选择给定属性具有给定值的所有元素。该值不能包含引号。   |
+-------------------------+--------------------------------------------------------+
| "[tag]"                 | 选择所有包含 "tag" 子元素的元素。只支持直系子元素。    |
+-------------------------+--------------------------------------------------------+
| "[tag='text']"          | 选择所有包含名为 "tag" 的子元素的元素，这些子元素（包  |
|                         | 括后代）的完整文 本内容等于给定的 "text" 。            |
+-------------------------+--------------------------------------------------------+
| "[position]"            | 选择位于给定位置的所有元素。 位置可以是一个整数 (1 表  |
|                         | 示首位)，表达式 "last()" (表示末位)，或者相对于末位的  |
|                         | 位置 (例如 "last()-1")。                               |
+-------------------------+--------------------------------------------------------+

谓词（方括号内的表达式）之前必须带有标签名称，星号或其他谓词。
"position" 谓词前必须有标签名称。


20.5.3. 参考
============


20.5.3.1. 函数
--------------

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

   注释元素工厂函数。 这个工厂函数可创建一个特殊元素，它将被标准序列化
   器当作 XML 注释来进行序列化。 注释字串可以是字节串或是 Unicode 字符
   串。 *text* 是包含注释字串的字符串。 返回一个表示注释的元素实例。

   请注意 "XMLParser" 会跳过输入中的注释而不会为其创建注释对象。
   "ElementTree" 将只在当使用某个 "Element" 方法向树插入了注释节点时才
   会包含注释节点。

xml.etree.ElementTree.dump(elem)

   将一个元素树或元素结构体写入到 sys.stdout。 此函数应当只被用于调试
   。

   实际输出格式是依赖于具体实现的。 在这个版本中，它将以普通 XML 文件
   的格式写入。

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

xml.etree.ElementTree.fromstring(text)

   Parses an XML section from a string constant.  Same as "XML()".
   *text* is a string containing XML data.  Returns an "Element"
   instance.

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

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

   3.2 新版功能.

xml.etree.ElementTree.iselement(element)

   Checks if an object appears to be a valid element object.
   *element* is an element instance.  Returns a true value if this is
   an element object.

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

   Parses an XML section into an element tree incrementally, and
   reports what's going on to the user.  *source* is a filename or
   *file object* containing XML data.  *events* is a sequence of
   events to report back.  The supported events are the strings
   ""start"", ""end"", ""start-ns"" and ""end-ns"" (the "ns" events
   are used to get detailed namespace information).  If *events* is
   omitted, only ""end"" events are reported. *parser* is an optional
   parser instance.  If not given, the standard "XMLParser" parser is
   used.  *parser* must be a subclass of "XMLParser" and can only use
   the default "TreeBuilder" as a target.  Returns an *iterator*
   providing "(event, elem)" pairs.

   请注意虽然 "iterparse()" 是以增量方式构建树，但它会对 *source* (或
   其所指定的文件) 发出阻塞式读取。 因此，它不适用于不可执行阻塞式读取
   的应用。 对于完全非阻塞式的解析，请参看 "XMLPullParser"。

   注解:

     "iterparse()" 只会确保当发出 "start" 事件时看到了开始标记的 ">"
     字符，因而在这个点上属性已被定义，但文本容和末尾属性还未被定义。
     这同样适用于元素的下级；它们可能存在也可能不存在。如果你需要已完
     全填充的元素，请改为查找 "end" 事件。

   3.4 版后已移除: *parser* 参数。

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" 会跳过输入中的处理指令而不会为其创建注释对象。
   "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", *, short_empty_elements=True)

   Generates a string representation of an XML element, including all
   subelements.  *element* is an "Element" instance.  *encoding* [1]
   is the output encoding (default is US-ASCII).  Use
   "encoding="unicode"" to generate a Unicode string (otherwise, a
   bytestring is generated).  *method* is either ""xml"", ""html"" or
   ""text"" (default is ""xml""). *short_empty_elements* has the same
   meaning as in "ElementTree.write()". Returns an (optionally)
   encoded string containing the XML data.

   3.4 新版功能: *short_empty_elements* 形参。

xml.etree.ElementTree.tostringlist(element, encoding="us-ascii", method="xml", *, short_empty_elements=True)

   Generates a string representation of an XML element, including all
   subelements.  *element* is an "Element" instance.  *encoding* [1]
   is the output encoding (default is US-ASCII).  Use
   "encoding="unicode"" to generate a Unicode string (otherwise, a
   bytestring is generated).  *method* is either ""xml"", ""html"" or
   ""text"" (default is ""xml""). *short_empty_elements* has the same
   meaning as in "ElementTree.write()". Returns a list of (optionally)
   encoded strings containing the XML data. It does not guarantee any
   specific sequence, except that "b"".join(tostringlist(element)) ==
   tostring(element)".

   3.2 新版功能.

   3.4 新版功能: *short_empty_elements* 形参。

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

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

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

   根据一个字符串常量解析 XML 的节，并且还将返回一个将元素的 id:s 映射
   到元素的字典。 *text* 是包含 XML 数据的字符串。 *parser* 是可选的解
   析器实例。 如果未给出，则会使用标准的 "XMLParser" 解析器。 返回一个
   包含 "Element" 实例和字典的元组。


20.5.3.2. 元素对象
------------------

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

   元素类。 这个类定义了 Element 接口，并提供了这个接口的引用实现。

   元素名、属性名和属性值可以是字节串或 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* 元素的 *text* 和 *tail* 属性均为 "None"，*b* 元素的 *text*
      为 ""1"" 而 *tail* 为 ""4""，*c* 元素的 *text* 为 ""2"" 而
      *tail* 为 "None"，*d* 元素的 *text* 为 "None" 而 *tail* 为 ""3""
      。

      要获取一个元素的内部文本，请参阅 "itertext()"，例如
      """.join(element.itertext())"。

      应用程序可以将任意对象存入这些属性。

   attrib

      一个包含元素属性的字典。 请注意虽然 *attrib* 值总是一个真正可变
      的 Python 字典，但 ElementTree 实现可以选择其他内部表示形式，并
      只在有需要时才创建字典。 为了发挥这种实现的优势，请在任何可能情
      况下使用下列字典方法。

   以下字典类方法可作用于元素属性。

   clear()

      重设一个元素。 此方法会移除所有子元素，清空所有属性，并将 text
      和 tail 属性设为 "None"。

   get(key, default=None)

      获取名为 *key* 的元素属性。

      返回属性的值，或者如果属性未找到则返回 *default*。

   items()

      将元素属性以 (name, value) 对序列的形式返回。 所返回属性的顺序任
      意。

   keys()

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

   set(key, value)

      将元素的 *key* 属性设为 *value*。

   以下方法作用于元素的下级（子元素）。

   append(subelement)

      将元素 *subelement* 添加到此元素的子元素内部列表。 如果
      *subelement* 不是一个 "Element" 则会引发 "TypeError"。

   extend(subelements)

      使用具有零个或多个元素的序列对象添加 *subelements*。 如果某个子
      元素不是 "Element" 则会引发 "TypeError"。

      3.2 新版功能.

   find(match, namespaces=None)

      Finds the first subelement matching *match*.  *match* may be a
      tag name or a path.  Returns an element instance or "None".
      *namespaces* is an optional mapping from namespace prefix to
      full name.

   findall(match, namespaces=None)

      Finds all matching subelements, by tag name or path.  Returns a
      list containing all matching elements in document order.
      *namespaces* is an optional mapping from namespace prefix to
      full name.

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

      Finds text for the first subelement matching *match*.  *match*
      may be a tag name or a path.  Returns the text content of the
      first matching element, or *default* if no element was found.
      Note that if the matching element has no text content an empty
      string is returned. *namespaces* is an optional mapping from
      namespace prefix to full name.

   getchildren()

      3.2 版后已移除: Use "list(elem)" or iteration.

   getiterator(tag=None)

      3.2 版后已移除: Use method "Element.iter()" instead.

   insert(index, subelement)

      将 *subelement* 插入到此元素的给定位置中。 如果 *subelement* 不
      是一个 "Element" 则会引发 "TypeError"。

   iter(tag=None)

      创建一个以当前元素为根元素的树的 *iterator*。 该迭代器将以文档（
      深度优先）顺序迭代此元素及其所有下级元素。 如果 *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"。 此行为将在未来的版本中发
   生变化。 请改用 "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")


20.5.3.3. 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()" 类似，从树的根节点开始。

   getiterator(tag=None)

      3.2 版后已移除: Use method "ElementTree.iter()" instead.

   getroot()

      返回这个树的根元素。

   iter(tag=None)

      创建并返回根元素的树结构迭代器。 该迭代器会以节顺序遍历这个树的
      所有元素。 *tag* 是要查找的标记（默认返回所有元素）。

   iterfind(match, namespaces=None)

      与 "Element.iterfind()" 类似，从树的根节点开始。

      3.2 新版功能.

   parse(source, parser=None)

      将一个外部 XML 节载入到此元素树。 *source* 是一个文件名或 *file
      object*。 *parser* 是可选的解析器实例。 如果未给出，则会使用标准
      的 "XMLParser" 解析器。 返回该节的根元素。

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

      将元素树以 XML 格式写入到文件。 *file* 为文件名，或是以写入模式
      打开的 *file object*。 *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* 的类型相冲突，如果它是一个打开
      的 *file object* 的话；请确保你不会试图写入字符串到二进制流或者
      反向操作。

      3.4 新版功能: *short_empty_elements* 形参。

这是将要被操作的 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")


20.5.3.4. 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" 实例是不透明的。


20.5.3.5. TreeBuilder 对象
--------------------------

class xml.etree.ElementTree.TreeBuilder(element_factory=None)

   Generic element structure builder.  This builder converts a
   sequence of start, data, and end method calls to a well-formed
   element structure.  You can use this class to build an element
   structure using a custom XML parser, or a parser for some other
   XML-like format.  *element_factory*, when given, must be a callable
   accepting two positional arguments: a tag and a dict of attributes.
   It is expected to return a new element instance.

   close()

      刷新构建器缓存，并返回最高层级的文档元素。 返回一个 "Element" 实
      例。

   data(data)

      将文本添加到当前元素。 *data* 为要添加的文本。 这应当是一个字节
      串或 Unicode 字符串。

   end(tag)

      结束当前元素。 *tag* 是元素名称。 返回已结束的元素。

   start(tag, attrs)

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

   In addition, a custom "TreeBuilder" object can provide the
   following method:

   doctype(name, pubid, system)

      处理一条 doctype 声明。 *name* 为 doctype 名称。 *pubid* 为公有
      标识。 *system* 为系统标识。 此方法不存在于默认的 "TreeBuilder"
      类中。

      3.2 新版功能.


20.5.3.6. XMLParser对象
-----------------------

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

   This class is the low-level building block of the module.  It uses
   "xml.parsers.expat" for efficient, event-based parsing of XML.  It
   can be fed XML data incrementally with the "feed()" method, and
   parsing events are translated to a push API - by invoking callbacks
   on the *target* object.  If *target* is omitted, the standard
   "TreeBuilder" is used. The *html* argument was historically used
   for backwards compatibility and is now deprecated.  If *encoding*
   [1] is given, the value overrides the encoding specified in the XML
   file.

   3.4 版后已移除: The *html* argument.  The remaining arguments
   should be passed via keyword to prepare for the removal of the
   *html* argument.

   close()

      结束向解析器提供数据。 返回调用在构造期间传入的 *target* 的
      "close()" 方法的结果；在默认情况下，这是最高层级的文档元素。

   doctype(name, pubid, system)

      3.2 版后已移除: Define the "TreeBuilder.doctype()" method on a
      custom TreeBuilder target.

   feed(data)

      将数据送入解析器。 *data* 是编码后的数据。

   "XMLParser.feed()" calls *target*'s "start(tag, attrs_dict)" method
   for each opening tag, its "end(tag)" method for each closing tag,
   and data is processed by method "data(data)".  "XMLParser.close()"
   calls *target*'s method "close()". "XMLParser" can be used not only
   for building a tree structure. This is an example of counting the
   maximum depth of an XML file:

      >>> 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


20.5.3.7. XMLPullParser对象
---------------------------

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

   A pull parser suitable for non-blocking applications.  Its input-
   side API is similar to that of "XMLParser", but instead of pushing
   calls to a callback target, "XMLPullParser" collects an internal
   list of parsing events and lets the user read from it. *events* is
   a sequence of events to report back.  The supported events are the
   strings ""start"", ""end"", ""start-ns"" and ""end-ns"" (the "ns"
   events are used to get detailed namespace information).  If
   *events* is omitted, only ""end"" events are reported.

   feed(data)

      将给定的字节数据送入解析器。

   close()

      通知解析器数据流已终结。 不同于 "XMLParser.close()"，此方法总是
      返回 "None"。 当解析器被关闭时任何还未被获取的事件仍可通过
      "read_events()" 被读取。

   read_events()

      Return an iterator over the events which have been encountered
      in the data fed to the parser.  The iterator yields "(event,
      elem)" pairs, where *event* is a string representing the type of
      event (e.g. ""end"") and *elem* is the encountered "Element"
      object.

      在之前对 "read_events()" 的调用中提供的事件将不会被再次产生。 事
      件仅当它们从迭代器中被取出时才会在内部队列中被消费，因此多个读取
      方对获取自 "read_events()" 的迭代器进行平行迭代将产生无法预料的
      结果。

   注解:

     "XMLPullParser" 只会确保当发出 "start" 事件时看到了开始标记的 ">"
     字符，因而在这个点上属性已被定义，但文本内容和末尾属性还未被定义
     。 这同样适用于元素的下级；它们可能存在也可能不存在。如果你需要已
     完全填充的元素，请改为查找 "end" 事件。

   3.4 新版功能.


20.5.3.8. 异常
--------------

class xml.etree.ElementTree.ParseError

   XML 解析器错误，由此模块中的多个解析方法在解析失败时引发。 此异常的
   实例的字符串表示将包含用户友好的错误消息。 此外，它将具有下列可用属
   性:

   code

      来自外部解析器的数字错误代码。 请参阅 "xml.parsers.expat" 的文档
      查看错误代码列表及它们的含义。

   position

      一个包含 *line*, *column* 数值的元组，指明错误发生的位置。

-[ 备注 ]-

[1] 包括在 XML 输出中的编码格式字符串应当符合适当的标准。 例如 "UTF-8"
    是有效的，但 "UTF8" 是无效的。 请参阅 https://www.w3.org/TR/2006
    /REC-xml11-20060816/#NT-EncodingDecl 和
    https://www.iana.org/assignments/character-sets/character-
    sets.xhtml。
