xml.dom — 文档对象模型 API

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


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

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

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

文档对象模型由 W3C 分阶段定义,在他们的术语中称为“级别”。Python 对 API 的映射主要基于 DOM 级别 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) 级别 2 规范

Python DOM API 所基于的 W3C 推荐。

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

xml.dom.minidom 支持的 DOM 的 W3C 推荐。

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 中的命名空间 (第 4 节) 所定义。

xml.dom.XMLNS_NAMESPACE

用于命名空间声明的命名空间 URI,如 文档对象模型 (DOM) 级别 2 核心规范 (第 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 对象

源文档中注释的表示。

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 的根),其子 Element 对象具有给定的 namespaceUriqualifiedNamedoctype 必须是由 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,该 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 对象提供一个作为其子节点列表,而 NodegetElementsByTagName()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 对象

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 和本地名称的后代(直接子节点、子节点的子节点等)。本地名称是命名空间中前缀之后的部分。

Element 对象

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

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 属性的适当值。

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

如果尝试以与 Namespaces in 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 推荐标准中定义的异常代码根据下表映射到上述异常

常量

Exception

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 推荐标准以及 OMG IDL 到 Python 的映射之间的符合性要求和关系。

类型映射

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

IDL 类型

Python 类型

boolean

boolint

int

int

long int

int

unsigned int

int

DOMString

strbytes

None

访问器方法

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

readonly attribute string someValue;
         attribute string anotherValue;

产生三个访问器函数:一个用于 someValue 的“获取”方法 (_get_someValue()),以及用于 anotherValue 的“获取”和“设置”方法 (_get_anotherValue()_set_anotherValue())。此映射尤其不要求 IDL 属性可作为普通 Python 属性访问:object.someValue 被要求工作,并且可能会引发 AttributeError

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

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

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