xml.dom
— 文档对象模型 API¶
文档对象模型 (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 属性也可以作为节点而不是简单的字符串进行操作。但是,您必须这样做的情况非常罕见,因此此用法尚未记录。
接口 |
节 |
用途 |
---|---|---|
|
底层实现的接口。 |
|
|
文档中大多数对象的基本接口。 |
|
|
节点序列的接口。 |
|
|
处理文档所需的声明信息。 |
|
|
表示整个文档的对象。 |
|
|
文档层次结构中的元素节点。 |
|
|
元素节点上的属性值节点。 |
|
|
源文档中注释的表示。 |
|
|
包含文档中文本内容的节点。 |
|
|
处理指令表示。 |
一个附加部分描述了在 Python 中使用 DOM 时定义的异常。
DOMImplementation 对象¶
DOMImplementation
接口提供了一种方法,让应用程序可以确定其正在使用的 DOM 中特定功能的可用性。DOM Level 2 还增加了使用 DOMImplementation
创建新的 Document
和 DocumentType
对象的能力。
- DOMImplementation.hasFeature(feature, version)¶
如果实现了由字符串对 feature 和 version 标识的功能,则返回
True
。
- DOMImplementation.createDocument(namespaceUri, qualifiedName, doctype)¶
返回一个新的
Document
对象(DOM 的根),其子Element
对象具有给定的 namespaceUri 和 qualifiedName。doctype 必须是由createDocumentType()
创建的DocumentType
对象,或None
。在 Python DOM API 中,前两个参数也可以是None
,以指示不创建Element
子节点。
- DOMImplementation.createDocumentType(qualifiedName, publicId, systemId)¶
返回一个新的
DocumentType
对象,该对象封装了给定的 qualifiedName、publicId 和 systemId 字符串,表示 XML 文档类型声明中包含的信息。
Node 对象¶
XML 文档的所有组件都是 Node
的子类。
- Node.nodeType¶
一个表示节点类型的整数。这些类型的符号常量位于
Node
对象上:ELEMENT_NODE
、ATTRIBUTE_NODE
、TEXT_NODE
、CDATA_SECTION_NODE
、ENTITY_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.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。如果 refChild 为None
,则将 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
对象提供一个作为其子节点列表,而 Node
的 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
,而不是此接口的实例。
DocumentType
是 Node
的特化,并添加了以下属性
- 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)¶
创建并返回一个包含作为参数传递的 target 和 data 的处理指令节点。与其他创建方法一样,此方法不会将节点插入到树中。
- Document.createAttribute(name)¶
创建并返回一个属性节点。此方法不将属性节点与任何特定元素关联。您必须在适当的
Element
对象上使用setAttributeNode()
来使用新创建的属性实例。
- Document.createAttributeNS(namespaceURI, qualifiedName)¶
创建并返回一个带命名空间的属性节点。tagName 可以有前缀。此方法不将属性节点与任何特定元素关联。您必须在适当的
Element
对象上使用setAttributeNode()
来使用新创建的属性实例。
- Document.getElementsByTagName(tagName)¶
搜索所有具有特定元素类型名称的后代(直接子节点、子节点的子节点等)。
- Document.getElementsByTagNameNS(namespaceURI, localName)¶
搜索所有具有特定命名空间 URI 和本地名称的后代(直接子节点、子节点的子节点等)。本地名称是命名空间中前缀之后的部分。
Element 对象¶
Element
是 Node
的子类,因此继承了该类的所有属性。
- Element.tagName¶
元素类型名称。在使用了命名空间的文档中,它可能包含冒号。该值是一个字符串。
- Element.getElementsByTagName(tagName)¶
与
Document
类中的同名方法相同。
- Element.getElementsByTagNameNS(namespaceURI, localName)¶
与
Document
类中的同名方法相同。
- Element.hasAttribute(name)¶
如果元素具有由 name 命名的属性,则返回
True
。
- Element.hasAttributeNS(namespaceURI, localName)¶
如果元素具有由 namespaceURI 和 localName 命名的属性,则返回
True
。
- Element.getAttribute(name)¶
以字符串形式返回由 name 命名的属性的值。如果不存在这样的属性,则返回一个空字符串,就像该属性没有值一样。
- Element.getAttributeNode(attrname)¶
返回由 attrname 命名的属性的
Attr
节点。
- Element.getAttributeNS(namespaceURI, localName)¶
以字符串形式返回由 namespaceURI 和 localName 命名的属性的值。如果不存在这样的属性,则返回一个空字符串,就像该属性没有值一样。
- Element.getAttributeNodeNS(namespaceURI, localName)¶
给定 namespaceURI 和 localName,将属性值作为节点返回。
- 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)¶
向元素添加一个新的属性节点,如果必要,当
namespaceURI
和localName
属性匹配时替换现有属性。如果发生替换,将返回旧的属性节点。如果 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*()
系列方法。
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 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
符合性¶
本节描述了 Python DOM API、W3C DOM 推荐标准以及 OMG IDL 到 Python 的映射之间的符合性要求和关系。
类型映射¶
DOM 规范中使用的 IDL 类型根据下表映射到 Python 类型。
IDL 类型 |
Python 类型 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
访问器方法¶
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 不要求实现强制执行此类要求。
Comment 对象¶
Comment
表示 XML 文档中的注释。它是Node
的子类,但不能有子节点。注释的内容作为字符串。该属性包含前导
<!-
-
和尾随-
->
之间的所有字符,但不包括它们。