xml.dom — 文档对象模型 API — Python 文档

来自菜鸟教程
Python/docs/3.10/library/xml.dom
跳转至:导航、​搜索

xml.dom — 文档对象模型 API

源代码: :source:`Lib/xml/dom/__init__.py`



文档对象模型或“DOM”是来自万维网联盟 (W3C) 的跨语言 API,用于访问和修改 XML 文档。 DOM 实现将 XML 文档呈现为树结构,或者允许客户端代码从头开始构建这样的结构。 然后它通过一组提供众所周知的接口的对象来访问结构。

DOM 对于随机访问应用程序非常有用。 SAX 一次只允许您查看文档的一部分。 如果您正在查看一个 SAX 元素,则无法访问另一个。 如果您正在查看文本节点,则无法访问包含元素。 当您编写 SAX 应用程序时,您需要在您自己的代码中的某个地方跟踪您的程序在文档中的位置。 SAX 不会为您做这件事。 此外,如果您需要在 XML 文档中向前看,那您就是不走运了。

在无法访问树的事件驱动模型中,某些应用程序根本不可能。 当然,您可以自己在 SAX 事件中构建某种树,但是 DOM 允许您避免编写该代码。 DOM 是 XML 数据的标准树表示。

W3C 正在分阶段或术语中的“级别”定义文档对象模型。 API 的 Python 映射基本上基于 DOM Level 2 推荐。

DOM 应用程序通常首先将一些 XML 解析为 DOM。 DOM 级别 1 根本没有涵盖如何实现这一点,级别 2 仅提供有限的改进:有一个 DOMImplementation 对象类提供对 Document 创建方法的访问,但没有办法以独立于实现的方式访问 XML 阅读器/解析器/文档构建器。 如果没有现有的 Document 对象,也没有明确定义的方法来访问这些方法。 在 Python 中,每个 DOM 实现都会提供一个函数 getDOMImplementation()。 DOM Level 3 添加了一个 Load/Store 规范,它定义了一个读取器的接口,但这在 Python 标准库中尚不可用。

一旦拥有 DOM 文档对象,就可以通过其属性和方法访问 XML 文档的各个部分。 这些属性在 DOM 规范中定义; 参考手册的这一部分描述了 Python 规范的解释。

W3C 提供的规范定义了 Java、ECMAScript 和 OMG IDL 的 DOM API。 此处定义的 Python 映射很大程度上基于规范的 IDL 版本,但不需要严格遵守(尽管实现可以自由地支持来自 IDL 的严格映射)。 有关映射要求的详细讨论,请参阅 一致性 部分。

也可以看看

文档对象模型 (DOM) 级别 2 规范
Python DOM API 所基于的 W3C 建议。
文档对象模型 (DOM) 级别 1 规范
W3C 对 xml.dom.minidom 支持的 DOM 的建议。
Python 语言映射规范
这指定了从 OMG IDL 到 Python 的映射。


模块内容

xml.dom 包含以下函数:

xml.dom.registerDOMImplementation(name, factory)
使用名称 name 注册 factory 函数。 工厂函数应该返回一个实现 DOMImplementation 接口的对象。 工厂函数可以每次都返回相同的对象,也可以为每次调用返回一个新对象,视具体实现而定(例如 如果该实现支持某些自定义)。
xml.dom.getDOMImplementation(name=None, features=())

返回一个合适的 DOM 实现。 name 要么是众所周知的,DOM 实现的模块名称,要么是 None。 如果不是None,则导入对应的模块,导入成功则返回DOMImplementation对象。 如果未给出名称,并且设置了环境变量 PYTHON_DOM,则该变量用于查找实现。

如果未给出名称,则会检查可用的实现以找到具有所需功能集的实现。 如果找不到实现,则引发 ImportError。 特征列表必须是一系列 (feature, version) 对,这些对传递给可用 DOMImplementation 对象上的 hasFeature() 方法。

还提供了一些便利常量:

xml.dom.EMPTY_NAMESPACE
用于指示没有命名空间与 DOM 中的节点相关联的值。 这通常作为节点的 namespaceURI 找到,或用作命名空间特定方法的 namespaceURI 参数。
xml.dom.XML_NAMESPACE
与保留前缀 xml 关联的命名空间 URI,如 XML 中的 Namespaces 所定义(第 4 节)。
xml.dom.XMLNS_NAMESPACE
命名空间声明的命名空间 URI,由 文档对象模型 (DOM) 级别 2 核心规范 (第 1.1.8 节)定义。
xml.dom.XHTML_NAMESPACE
XHTML 1.0: The Extensible HyperText Markup Language(第 3.1.1 节)定义的 XHTML 命名空间的 URI。

此外,xml.dom 包含一个基本的 Node 类和 DOM 异常类。 本模块提供的 Node 类没有实现 DOM 规范定义的任何方法或属性; 具体的 DOM 实现必须提供这些。 作为本模块一部分提供的 Node 类确实提供了用于具体 Node 对象上的 nodeType 属性的常量; 它们位于类内而不是模块级别以符合 DOM 规范。


DOM 中的对象

DOM 的权威文档是来自 W3C 的 DOM 规范。

请注意,DOM 属性也可以作为节点而不是简单的字符串进行操作。 但是,您必须执行此操作的情况相当少见,因此尚未记录此用法。

界面 部分 目的
DOMImplementation DOM 实现对象 底层实现的接口。
Node 节点对象 文档中大多数对象的基本接口。
NodeList 节点列表对象 一系列节点的接口。
DocumentType 文档类型对象 有关处理文档所需的声明的信息。
Document 文档对象 代表整个文档的对象。
Element 元素对象 文档层次结构中的元素节点。
Attr 属性对象 元素节点上的属性值节点。
Comment 评论对象 在源文档中表示注释。
Text 文本和 CDATASection 对象 包含来自文档的文本内容的节点。
ProcessingInstruction 处理指令对象 处理指令表示。

附加部分描述了为在 Python 中使用 DOM 而定义的异常。

DOM 实现对象

DOMImplementation 接口为应用程序提供了一种方法来确定它们正在使用的 DOM 中特定功能的可用性。 DOM Level 2 添加了使用 DOMImplementation 创建新的 DocumentDocumentType 对象的能力。

DOMImplementation.hasFeature(feature, version)
如果实现了由字符串对 featureversion 标识的特征,则返回 True
DOMImplementation.createDocument(namespaceUri, qualifiedName, doctype)
返回一个新的 Document 对象(DOM 的根),其子对象 Element 具有给定的 namespaceUriqualifiedNamedoctype 必须是由 createDocumentType()None 创建的 DocumentType 对象。 在 Python DOM API 中,前两个参数也可以是 None 以指示不创建 Element 子节点。
DOMImplementation.createDocumentType(qualifiedName, publicId, systemId)
返回一个新的 DocumentType 对象,该对象封装了给定的 qualifiedNamepublicIdsystemId 字符串,表示包含在 XML 文档类型声明中的信息.


节点对象

XML 文档的所有组件都是 Node 的子类。

Node.nodeType
表示节点类型的整数。 类型的符号常量位于 Node 对象上:ELEMENT_NODEATTRIBUTE_NODETEXT_NODECDATA_SECTION_NODEENTITY_NODE , PROCESSING_INSTRUCTION_NODE, COMMENT_NODE, DOCUMENT_NODE, DOCUMENT_TYPE_NODE, NOTATION_NODE。 这是一个只读属性。
Node.parentNode
当前节点的父节点,或文档节点的 None。 该值始终是 Node 对象或 None。 对于 Element 节点,这将是父元素,根元素除外,在这种情况下,它将是 Document 对象。 对于 Attr 节点,这始终是 None。 这是一个只读属性。
Node.attributes
属性对象的 NamedNodeMap。 只有元素具有此实际值; 其他人为此属性提供 None。 这是一个只读属性。
Node.previousSibling
紧跟在此节点之前的节点具有相同的父节点。 例如,带有结束标签的元素正好位于 self 元素的开始标签之前。 当然,XML 文档不仅仅由元素组成,因此前一个同级可以是文本、注释或其他内容。 如果此节点是父节点的第一个子节点,则此属性将为 None。 这是一个只读属性。
Node.nextSibling
紧跟在此节点之后的节点具有相同的父节点。 另见 previousSibling。 如果这是父级的最后一个子级,则此属性将为 None。 这是一个只读属性。
Node.childNodes
此节点中包含的节点列表。 这是一个只读属性。
Node.firstChild
节点的第一个子节点,如果有的话,或者 None。 这是一个只读属性。
Node.lastChild
节点的最后一个子节点,如果有的话,或者 None。 这是一个只读属性。
Node.localName
冒号后面的 tagName 部分(如果有),否则整个 tagName。 该值是一个字符串。
Node.prefix
冒号前的 tagName 部分(如果有),否则为空字符串。 该值是一个字符串,或 None
Node.namespaceURI
与元素名称关联的命名空间。 这将是一个字符串或 None。 这是一个只读属性。
Node.nodeName
这对每个节点类型都有不同的含义; 有关详细信息,请参阅 DOM 规范。 您始终可以从其他属性(例如元素的 tagName 属性或属性的 name 属性)获取您在此处获得的信息。 对于所有节点类型,此属性的值将是字符串或 None。 这是一个只读属性。
Node.nodeValue
这对每个节点类型都有不同的含义; 有关详细信息,请参阅 DOM 规范。 情况与 nodeName 类似。 该值是一个字符串或 None
Node.hasAttributes()
如果节点有任何属性,则返回 True
Node.hasChildNodes()
如果节点有任何子节点,则返回 True
Node.isSameNode(other)

如果 other 引用与此节点相同的节点,则返回 True。 这对于使用任何类型代理架构的 DOM 实现特别有用(因为多个对象可以引用同一个节点)。

笔记

这是基于提议的 DOM Level 3 API,该 API 仍处于“工作草案”阶段,但这个特定的接口似乎没有争议。 W3C 的更改不一定会影响 Python DOM 接口中的此方法(尽管也将支持任何新的 W3C API)。

Node.appendChild(newChild)
在子节点列表的末尾向该节点添加一个新的子节点,返回 newChild。 如果该节点已经在树中,则首先将其删除。
Node.insertBefore(newChild, refChild)
在现有子节点之前插入一个新的子节点。 肯定是refChild是这个节点的子节点; 如果不是,则引发 ValueError。 返回 newChild。 如果 refChildNone,它会在孩子列表的末尾插入 newChild
Node.removeChild(oldChild)
删除一个子节点。 oldChild 必须是这个节点的子节点; 如果不是,则引发 ValueErroroldChild 成功返回。 如果不再使用 oldChild,则应调用其 unlink() 方法。
Node.replaceChild(newChild, oldChild)
用新节点替换现有节点。 肯定是oldChild是这个节点的子节点; 如果不是,则引发 ValueError
Node.normalize()
连接相邻的文本节点,以便将所有文本段存储为单个 Text 实例。 这简化了许多应用程序从 DOM 树处理文本的过程。
Node.cloneNode(deep)
克隆这个节点。 设置 deep 也意味着克隆所有子节点。 这将返回克隆。


节点列表对象

A NodeList 表示节点序列。 这些对象在 DOM Core 推荐中以两种方式使用:Element 对象提供一个作为其子节点列表,以及 Node 返回具有该接口的对象来表示查询结果。

DOM Level 2 建议为这些对象定义了一种方法和一种属性:

NodeList.item(i)
从序列中返回第 i 个项目(如果有)或 None。 索引 i 不允许小于零或大于等于序列的长度。
NodeList.length
序列中的节点数。

此外,Python DOM 接口需要提供一些额外的支持,以允许将 NodeList 对象用作 Python 序列。 所有 NodeList 实现必须包括对 __len__()__getitem__() 的支持; 这允许在 for 语句中迭代 NodeList,并适当支持 len() 内置函数。

如果 DOM 实现支持修改文档,则 NodeList 实现还必须支持 __setitem__()__delitem__() 方法。


文档类型对象

关于文档声明的符号和实体的信息(包括外部子集,如果解析器使用它并且可以提供信息)可以从 DocumentType 对象中获得。 文档的 DocumentType 可从 Document 对象的 doctype 属性获得; 如果文档没有 DOCTYPE 声明,则文档的 doctype 属性将设置为 None 而不是此接口的实例。

DocumentTypeNode的特化,增加了以下属性:

DocumentType.publicId
文档类型定义的外部子集的公共标识符。 这将是一个字符串或 None
DocumentType.systemId
文档类型定义的外部子集的系统标识符。 这将是字符串形式的 URI,或 None
DocumentType.internalSubset
给出文档中完整内部子集的字符串。 这不包括包含子集的括号。 如果文档没有内部子集,这应该是 None
DocumentType.name
DOCTYPE 声明中给出的根元素的名称(如果存在)。
DocumentType.entities
这是一个 NamedNodeMap,给出了外部实体的定义。 对于多次定义的实体名称,仅提供第一个定义(根据 XML 建议的要求忽略其他定义)。 如果解析器未提供信息,或者未定义实体,则这可能是 None
DocumentType.notations
这是一个 NamedNodeMap 给出符号的定义。 对于多次定义的表示法名称,仅提供第一个定义(根据 XML 建议的要求忽略其他定义)。 如果解析器未提供信息,或者未定义符号,则这可能是 None


文档对象

一个 Document 代表一个完整的 XML 文档,包括它的组成元素、属性、处理指令、注释等。 请记住,它继承了 Node 的属性。

Document.documentElement
文档的唯一根元素。
Document.createElement(tagName)
创建并返回一个新的元素节点。 元素在创建时不会插入到文档中。 您需要使用其他方法之一显式插入它,例如 insertBefore()appendChild()
Document.createElementNS(namespaceURI, tagName)
创建并返回一个带有命名空间的新元素。 tagName 可能有前缀。 元素在创建时不会插入到文档中。 您需要使用其他方法之一显式插入它,例如 insertBefore()appendChild()
Document.createTextNode(data)
创建并返回一个包含作为参数传递的数据的文本节点。 与其他创建方法一样,此方法不会将节点插入树中。
Document.createComment(data)
创建并返回一个包含作为参数传递的数据的注释节点。 与其他创建方法一样,此方法不会将节点插入树中。
Document.createProcessingInstruction(target, data)
创建并返回一个处理指令节点,其中包含作为参数传递的 targetdata。 与其他创建方法一样,此方法不会将节点插入树中。
Document.createAttribute(name)
创建并返回一个属性节点。 此方法不会将属性节点与任何特定元素相关联。 您必须在适当的 Element 对象上使用 setAttributeNode() 才能使用新创建的属性实例。
Document.createAttributeNS(namespaceURI, qualifiedName)
创建并返回具有命名空间的属性节点。 tagName 可能有前缀。 此方法不会将属性节点与任何特定元素相关联。 您必须在适当的 Element 对象上使用 setAttributeNode() 才能使用新创建的属性实例。
Document.getElementsByTagName(tagName)
搜索具有特定元素类型名称的所有后代(直接子项、子项的子项等)。
Document.getElementsByTagNameNS(namespaceURI, localName)
搜索具有特定命名空间 URI 和本地名称的所有后代(直接子代、子代的子代等)。 localname 是前缀之后的命名空间的一部分。


元素对象

ElementNode 的子类,因此继承了该类的所有属性。

Element.tagName
元素类型名称。 在使用名称空间的文档中,它可能有冒号。 该值是一个字符串。
Element.getElementsByTagName(tagName)
Document 类中的等效方法相同。
Element.getElementsByTagNameNS(namespaceURI, localName)
Document 类中的等效方法相同。
Element.hasAttribute(name)
如果元素具有由 name 命名的属性,则返回 True
Element.hasAttributeNS(namespaceURI, localName)
如果元素具有由 namespaceURIlocalName 命名的属性,则返回 True
Element.getAttribute(name)
以字符串形式返回由 name 命名的属性的值。 如果不存在这样的属性,则返回一个空字符串,就好像该属性没有值一样。
Element.getAttributeNode(attrname)
返回由 attrname 命名的属性的 Attr 节点。
Element.getAttributeNS(namespaceURI, localName)
以字符串形式返回由 namespaceURIlocalName 命名的属性的值。 如果不存在这样的属性,则返回一个空字符串,就好像该属性没有值一样。
Element.getAttributeNodeNS(namespaceURI, localName)
返回一个属性值作为节点,给定 namespaceURIlocalName
Element.removeAttribute(name)
按名称删除属性。 如果没有匹配的属性,则会引发 NotFoundErr
Element.removeAttributeNode(oldAttr)
从属性列表中删除并返回 oldAttr(如果存在)。 如果 oldAttr 不存在,则引发 NotFoundErr
Element.removeAttributeNS(namespaceURI, localName)
按名称删除属性。 请注意,它使用 localName,而不是 qname。 如果没有匹配的属性,则不会引发异常。
Element.setAttribute(name, value)
从字符串设置属性值。
Element.setAttributeNode(newAttr)
向元素添加新属性节点,如果 name 属性匹配,则必要时替换现有属性。 如果发生替换,将返回旧的属性节点。 如果 newAttr 已在使用中,则会引发 InuseAttributeErr
Element.setAttributeNodeNS(newAttr)
向元素添加新属性节点,如果 namespaceURIlocalName 属性匹配,则必要时替换现有属性。 如果发生替换,将返回旧的属性节点。 如果 newAttr 已在使用中,则会引发 InuseAttributeErr
Element.setAttributeNS(namespaceURI, qname, value)
从字符串设置属性值,给定 namespaceURIqname。 请注意,qname 是整个属性名称。 这与上面的不同。


属性对象

Attr继承自Node,所以继承了它的所有属性。

Attr.name
属性名称。 在使用名称空间的文档中,它可能包含一个冒号。
Attr.localName
冒号后面的名称部分(如果有),否则为整个名称。 这是一个只读属性。
Attr.prefix
冒号前面的名称部分(如果有),否则为空字符串。
Attr.value
属性的文本值。 这是 nodeValue 属性的同义词。


NamedNodeMap 对象

NamedNodeMap 不是 继承自 Node

NamedNodeMap.length
属性列表的长度。
NamedNodeMap.item(index)
返回具有特定索引的属性。 获取属性的顺序是任意的,但在 DOM 的生命周期内是一致的。 每个项目都是一个属性节点。 使用 value 属性获取其值。

还有一些实验方法可以为此类提供更多映射行为。 您可以使用它们,也可以在 Element 对象上使用标准化的 getAttribute*() 系列方法。


评论对象

Comment 表示 XML 文档中的注释。 它是 Node 的子类,但不能有子节点。

Comment.data
注释的内容作为字符串。 该属性包含前导 <!-- 和尾随 --> 之间的所有字符,但不包括它们。


文本和 CDATASection 对象

Text 接口表示 XML 文档中的文本。 如果解析器和 DOM 实现支持 DOM 的 XML 扩展,则包含在 CDATA 标记部分中的部分文本存储在 CDATASection 对象中。 这两个接口是相同的,但为 nodeType 属性提供不同的值。

这些接口扩展了 Node 接口。 他们不能有子节点。

Text.data
文本节点的内容作为字符串。

笔记

使用 CDATASection 节点并不表示该节点代表一个完整的 CDATA 标记部分,仅表示该节点的内容是 CDATA 部分的一部分。 单个 CDATA 部分可以由文档树中的多个节点表示。 无法确定两个相邻的 CDATASection 节点是否代表不同的 CDATA 标记部分。


处理指令对象

代表XML文档中的一条处理指令; 这继承自 Node 接口并且不能有子节点。

ProcessingInstruction.target
处理指令的内容直到第一个空白字符。 这是一个只读属性。
ProcessingInstruction.data
第一个空格字符后面的处理指令的内容。


例外

DOM 级别 2 建议定义了一个异常 DOMException 和许多允许应用程序确定发生哪种错误的常量。 DOMException 实例带有 code 属性,该属性为特定异常提供适当的值。

Python DOM 接口提供了常量,但也扩展了异常集,以便为 DOM 定义的每个异常代码都存在一个特定的异常。 实现必须引发适当的特定异常,每个异常都带有 code 属性的适当值。

exception xml.dom.DOMException
用于所有特定 DOM 异常的基本异常类。 这个异常类不能直接实例化。
exception xml.dom.DomstringSizeErr
当指定的文本范围不适合字符串时引发。 这在 Python DOM 实现中使用是未知的,但可以从不是用 Python 编写的 DOM 实现接收。
exception xml.dom.HierarchyRequestErr
当尝试插入节点类型不允许的节点时引发。
exception xml.dom.IndexSizeErr
当方法的索引或大小参数为负或超过允许值时引发。
exception xml.dom.InuseAttributeErr
当尝试插入已经存在于文档其他地方的 Attr 节点时引发。
exception xml.dom.InvalidAccessErr
如果基础对象不支持参数或操作,则引发。
exception xml.dom.InvalidCharacterErr
当字符串参数包含 XML 1.0 建议使用的上下文中不允许的字符时,会引发此异常。 例如,尝试使用元素类型名称中的空格创建 Element 节点将导致引发此错误。
exception xml.dom.InvalidModificationErr
在尝试修改节点类型时引发。
exception xml.dom.InvalidStateErr
当尝试使用未定义或不再可用的对象时引发。
exception xml.dom.NamespaceErr
如果尝试以 XML 中的 命名空间建议不允许的方式更改任何对象,则会引发此异常。
exception xml.dom.NotFoundErr
引用上下文中不存在节点时的异常。 例如, NamedNodeMap.removeNamedItem() 如果传入的节点在地图中不存在,则会引发此问题。
exception xml.dom.NotSupportedErr
当实现不支持请求的对象或操作类型时引发。
exception xml.dom.NoDataAllowedErr
如果为不支持数据的节点指定了数据,则会引发此问题。
exception xml.dom.NoModificationAllowedErr
在尝试修改不允许修改的对象(例如只读节点)时引发。
exception xml.dom.SyntaxErr
在指定无效或非法字符串时引发。
exception xml.dom.WrongDocumentErr
当节点插入到当前所属的不同文档时引发,并且实现不支持将节点从一个文档迁移到另一个文档。

DOM 推荐中定义的异常代码根据下表映射到上述异常:

持续的 例外
DOMSTRING_SIZE_ERR DomstringSizeErr
HIERARCHY_REQUEST_ERR HierarchyRequestErr
INDEX_SIZE_ERR IndexSizeErr
INUSE_ATTRIBUTE_ERR InuseAttributeErr
INVALID_ACCESS_ERR InvalidAccessErr
INVALID_CHARACTER_ERR InvalidCharacterErr
INVALID_MODIFICATION_ERR InvalidModificationErr
INVALID_STATE_ERR InvalidStateErr
NAMESPACE_ERR NamespaceErr
NOT_FOUND_ERR NotFoundErr
NOT_SUPPORTED_ERR NotSupportedErr
NO_DATA_ALLOWED_ERR NoDataAllowedErr
NO_MODIFICATION_ALLOWED_ERR NoModificationAllowedErr
SYNTAX_ERR SyntaxErr
WRONG_DOCUMENT_ERR WrongDocumentErr


一致性

本节描述了 Python DOM API、W3C DOM 建议和 Python 的 OMG IDL 映射之间的一致性要求和关系。

类型映射

DOM 规范中使用的 IDL 类型根据下表映射到 Python 类型。

IDL 类型 Python 类型
boolean boolint
int int
long int int
unsigned int int
DOMString strbytes
null None


存取方法

从 OMG IDL 到 Python 的映射定义了 IDL attribute 声明的访问器函数,这与 Java 映射的方式非常相似。 映射 IDL 声明

readonly attribute string someValue;
         attribute string anotherValue;

产生三个访问器函数:someValue (_get_someValue()) 的“get”方法,以及 anotherValue (_get_anotherValue()_set_anotherValue())。 特别是,映射不要求 IDL 属性可以作为普通 Python 属性访问:object.someValuenot 需要工作,并且可能会引发 AttributeError

然而,Python DOM API 确实 要求正常的属性访问工作。 这意味着 Python IDL 编译器生成的典型代理不太可能工作,如果通过 CORBA 访问 DOM 对象,则客户端可能需要包装器对象。 虽然这确实需要对 CORBA DOM 客户端进行一些额外的考虑,但具有在 Python 中通过 CORBA 使用 DOM 的经验的实现者并不认为这是一个问题。 声明为 readonly 的属性可能不会限制所有 DOM 实现中的写访问。

在 Python DOM API 中,不需要访问器函数。 如果提供,它们应该采用 Python IDL 映射定义的形式,但这些方法被认为是不必要的,因为属性可以直接从 Python 访问。 永远不应为 readonly 属性提供“设置”访问器。

IDL 定义并没有完全体现 W3C DOM API 的要求,例如某些对象的概念,例如 getElementsByTagName() 的返回值,是“活的”。 Python DOM API 不需要实现来强制执行此类要求。