xml.dom
— 文档对象模型 API¶
文档对象模型,或“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 属性也可以作为节点而不是简单的字符串进行操作。 但是,您很少需要这样做,因此此用法尚未记录。
接口 |
章节 |
目的 |
---|---|---|
|
底层实现的接口。 |
|
|
文档中大多数对象的基本接口。 |
|
|
节点序列的接口。 |
|
|
关于处理文档所需的声明的信息。 |
|
|
表示整个文档的对象。 |
|
|
文档层次结构中的元素节点。 |
|
|
元素节点上的属性值节点。 |
|
|
源文档中注释的表示。 |
|
|
包含文档文本内容的节点。 |
|
|
处理指令表示。 |
还有一个额外的部分描述了在 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 的根),其中包含一个具有给定 namespaceUri 和 qualifiedName 的子Element
对象。 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,但这个特定的接口似乎没有争议。 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
对象将其子节点列表作为其中之一提供,并且 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
表示整个 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
是 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
属性的适当值。
- 异常 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.NotFoundErr¶
当节点在引用的上下文中不存在时引发的异常。例如,如果传入的节点在映射中不存在,
NamedNodeMap.removeNamedItem()
将引发此异常。
- 异常 xml.dom.NotSupportedErr¶
当实现不支持请求的对象类型或操作时引发。
- 异常 xml.dom.NoDataAllowedErr¶
如果为不支持数据的节点指定数据,则会引发此异常。
- 异常 xml.dom.NoModificationAllowedErr¶
尝试修改不允许修改的对象(例如只读节点)时引发。
- 异常 xml.dom.SyntaxErr¶
当指定无效或非法字符串时引发。
- 异常 xml.dom.WrongDocumentErr¶
当节点插入到与当前所属文档不同的文档中,并且实现不支持将节点从一个文档迁移到另一个文档时引发。
DOM 建议中定义的异常代码根据下表映射到上述异常
常量 |
异常 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
一致性¶
本节描述了 Python DOM API、W3C DOM 建议以及 Python 的 OMG IDL 映射之间的一致性要求和关系。
类型映射¶
DOM 规范中使用的 IDL 类型根据下表映射到 Python 类型。
IDL 类型 |
Python 类型 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
访问器方法¶
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 不要求实现强制执行此类要求。
Comment 对象¶
Comment
表示 XML 文档中的注释。它是Node
的子类,但不能有子节点。注释的内容,以字符串形式表示。该属性包含前导
<!-
-
和尾随-
->
之间的所有字符,但不包括它们。