xml.dom — 文档对象模型 API

源代码: 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 Level 1 完全没有涵盖如何完成此操作,并且 Level 2 仅提供了有限的改进:存在一个 DOMImplementation 对象类,该类提供对 Document 创建方法的访问,但没有以独立于实现的方式访问 XML 读取器/解析器/文档构建器的方法。在没有现有 Document 对象的情况下,也没有定义明确的方法来访问这些方法。在 Python 中,每个 DOM 实现都会提供一个函数 getDOMImplementation()。DOM Level 3 添加了一个加载/存储规范,该规范定义了读取器的接口,但此规范尚未在 Python 标准库中提供。

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

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

另请参阅

文档对象模型 (DOM) Level 2 规范

Python DOM API 基于的 W3C 建议。

文档对象模型 (DOM) Level 1 规范

xml.dom.minidom 支持的 DOM 的 W3C 建议。

Python 语言映射规范

这指定了从 OMG IDL 到 Python 的映射。

模块内容

xml.dom 包含以下函数

xml.dom.registerDOMImplementation(name, factory)

使用名称 name 注册 factory 函数。factory 函数应返回一个实现 DOMImplementation 接口的对象。factory 函数可以每次返回相同的对象,也可以每次调用返回一个新的对象,这取决于具体的实现(例如,如果该实现支持某些自定义)。

xml.dom.getDOMImplementation(name=None, features=())

返回合适的 DOM 实现。name 是众所周知的,DOM 实现的模块名称或 None。如果不是 None,则导入相应的模块,如果导入成功,则返回一个 DOMImplementation 对象。如果未指定名称,并且如果设置了环境变量 PYTHON_DOM,则使用此变量来查找实现。

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

还提供了一些方便的常量

xml.dom.EMPTY_NAMESPACE

用于指示 DOM 中没有命名空间与节点关联的值。这通常作为节点的 namespaceURI 找到,或者用作命名空间特定方法的 namespaceURI 参数。

xml.dom.XML_NAMESPACE

与保留前缀 xml 关联的命名空间 URI,如 XML 中的命名空间(第 4 节)中所定义。

xml.dom.XMLNS_NAMESPACE

命名空间声明的命名空间 URI,如 文档对象模型 (DOM) Level 2 Core 规范(第 1.1.8 节)中所定义。

xml.dom.XHTML_NAMESPACE

XHTML 命名空间的 URI,如 XHTML 1.0:可扩展超文本标记语言(第 3.1.1 节)中所定义。

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

DOM 中的对象

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

请注意,DOM 属性也可以作为节点而不是简单的字符串进行操作。 但是,您很少需要这样做,因此此用法尚未记录。

接口

章节

目的

DOMImplementation

DOMImplementation 对象

底层实现的接口。

Node

Node 对象

文档中大多数对象的基本接口。

NodeList

NodeList 对象

节点序列的接口。

DocumentType

DocumentType 对象

关于处理文档所需的声明的信息。

Document

Document 对象

表示整个文档的对象。

Element

Element 对象

文档层次结构中的元素节点。

Attr

Attr 对象

元素节点上的属性值节点。

Comment

Comment 对象

源文档中注释的表示。

Text

Text 和 CDATASection 对象

包含文档文本内容的节点。

ProcessingInstruction

ProcessingInstruction 对象

处理指令表示。

还有一个额外的部分描述了在 Python 中使用 DOM 定义的异常。

DOMImplementation 对象

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

DOMImplementation.hasFeature(feature, version)

如果由字符串 featureversion 对标识的功能已实现,则返回 True

DOMImplementation.createDocument(namespaceUri, qualifiedName, doctype)

返回一个新的 Document 对象(DOM 的根),其中包含一个具有给定 namespaceUriqualifiedName 的子 Element 对象。 doctype 必须是由 createDocumentType() 创建的 DocumentType 对象,或者为 None。 在 Python DOM API 中,前两个参数也可以为 None,以指示不创建 Element 子项。

DOMImplementation.createDocumentType(qualifiedName, publicId, systemId)

返回一个新的 DocumentType 对象,该对象封装给定的 qualifiedNamepublicIdsystemId 字符串,表示 XML 文档类型声明中包含的信息。

Node 对象

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

Node.nodeType

表示节点类型的整数。类型的符号常量位于 Node 对象上:ELEMENT_NODEATTRIBUTE_NODETEXT_NODECDATA_SECTION_NODEENTITY_NODEPROCESSING_INSTRUCTION_NODECOMMENT_NODEDOCUMENT_NODEDOCUMENT_TYPE_NODENOTATION_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,但这个特定的接口似乎没有争议。 W3C 的更改不一定会影响 Python DOM 接口中的此方法(尽管也会支持此方面的任何新的 W3C API)。

Node.appendChild(newChild)

将新的子节点添加到此节点子节点列表的末尾,并返回 newChild。如果该节点已在树中,则会先将其移除。

Node.insertBefore(newChild, refChild)

在现有子节点之前插入一个新的子节点。 必须保证 refChild 是此节点的子节点;否则,将引发 ValueError。 返回 newChild。 如果 refChildNone,则将 newChild 插入到子节点列表的末尾。

Node.removeChild(oldChild)

移除一个子节点。 oldChild 必须是此节点的子节点;否则,将引发 ValueError。 成功后返回 oldChild。 如果 oldChild 不再使用,则应调用其 unlink() 方法。

Node.replaceChild(newChild, oldChild)

用新节点替换现有节点。 必须保证 oldChild 是此节点的子节点;否则,将引发 ValueError

Node.normalize()

连接相邻的文本节点,以便将所有文本段存储为单个 Text 实例。 这简化了许多应用程序从 DOM 树处理文本的过程。

Node.cloneNode(deep)

克隆此节点。 设置 deep 表示同时克隆所有子节点。 这将返回克隆的节点。

NodeList 对象

NodeList 表示一个节点序列。 这些对象在 DOM Core 建议中以两种方式使用:Element 对象将其子节点列表作为其中之一提供,并且 getElementsByTagName()getElementsByTagNameNS() 方法返回具有此接口的对象来表示查询结果。

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 对象中获取。 文档的 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 和本地名称的所有后代(直接子元素、子元素的子元素等)。本地名称是前缀后的命名空间部分。

元素对象

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)

从字符串设置一个属性值,给定一个 namespaceURI 和一个 qname。请注意,qname 是完整的属性名称。这与上述不同。

Attr 对象

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

Attr.name

属性名称。在使用命名空间的文档中,它可能包含冒号。

Attr.localName

如果存在冒号,则为冒号后面的名称部分,否则为整个名称。这是一个只读属性。

Attr.prefix

如果存在冒号,则为冒号前面的名称部分,否则为空字符串。

Attr.value

属性的文本值。这是 nodeValue 属性的同义词。

NamedNodeMap 对象

NamedNodeMap 继承自 Node

NamedNodeMap.length

属性列表的长度。

NamedNodeMap.item(index)

返回具有特定索引的属性。获取属性的顺序是任意的,但在 DOM 的生命周期内将保持一致。每个项目都是一个属性节点。使用 value 属性获取其值。

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

Comment 对象

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

Comment.data

注释的内容,以字符串形式表示。该属性包含前导 <!-- 和尾随 --> 之间的所有字符,但不包括它们。

Text 和 CDATASection 对象

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

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

Text.data

文本节点的内容,以字符串形式表示。

注意

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

ProcessingInstruction 对象

表示 XML 文档中的处理指令;它继承自 Node 接口,并且不能有子节点。

ProcessingInstruction.target

处理指令的内容,直到第一个空格字符。这是一个只读属性。

ProcessingInstruction.data

处理指令的内容,在第一个空格字符之后。

异常

DOM Level 2 推荐定义了一个异常,DOMException,以及许多常量,允许应用程序确定发生了哪种类型的错误。DOMException 实例携带一个 code 属性,该属性为特定异常提供适当的值。

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

异常 xml.dom.DOMException

用于所有特定 DOM 异常的基类异常。此异常类不能直接实例化。

异常 xml.dom.DomstringSizeErr

当指定的文本范围不适合字符串时引发。这在 Python DOM 实现中尚未使用,但可能从非 Python 编写的 DOM 实现中接收到。

异常 xml.dom.HierarchyRequestErr

当尝试插入节点,而该节点的类型不允许时引发。

异常 xml.dom.IndexSizeErr

当方法的索引或大小参数为负数或超出允许值时引发。

异常 xml.dom.InuseAttributeErr

当尝试插入一个 Attr 节点,而该节点已存在于文档的其他位置时引发。

异常 xml.dom.InvalidAccessErr

如果参数或操作在底层对象上不受支持,则引发。

异常 xml.dom.InvalidCharacterErr

当字符串参数包含 XML 1.0 建议中不允许的字符时,会引发此异常。例如,尝试创建一个元素类型名称中带有空格的 Element 节点将导致引发此错误。

异常 xml.dom.InvalidModificationErr

当尝试修改节点的类型时引发。

异常 xml.dom.InvalidStateErr

当尝试使用未定义或不再可用的对象时引发。

异常 xml.dom.NamespaceErr

如果尝试以不符合 XML 命名空间建议的方式更改任何对象,则会引发此异常。

异常 xml.dom.NotFoundErr

当节点在引用的上下文中不存在时引发的异常。例如,如果传入的节点在映射中不存在,NamedNodeMap.removeNamedItem() 将引发此异常。

异常 xml.dom.NotSupportedErr

当实现不支持请求的对象类型或操作时引发。

异常 xml.dom.NoDataAllowedErr

如果为不支持数据的节点指定数据,则会引发此异常。

异常 xml.dom.NoModificationAllowedErr

尝试修改不允许修改的对象(例如只读节点)时引发。

异常 xml.dom.SyntaxErr

当指定无效或非法字符串时引发。

异常 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” 方法 (_get_someValue()),以及 anotherValue 的 “get” 和 “set” 方法 (_get_anotherValue()_set_anotherValue())。特别是,该映射不要求 IDL 属性可以作为普通的 Python 属性访问:不要求 object.someValue 可以工作,并且可能会引发 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 不要求实现强制执行此类要求。