xml.dom
— 文档对象模型 API¶
文档对象模型(DOM)是万维网联盟(W3C)推出的一种跨语言 API,用于访问和修改 XML 文档。DOM 实现将 XML 文档表示为树结构,或允许客户端代码从头构建此类结构。然后,它通过一组提供众所周知接口的对象来访问该结构。
DOM 对于随机访问应用程序非常有用。SAX 只允许您一次查看文档的一部分。如果您正在查看一个 SAX 元素,则无法访问另一个元素。如果您正在查看一个文本节点,则无法访问包含它的元素。在编写 SAX 应用程序时,您需要在自己的代码中的某个位置跟踪程序在文档中的位置。SAX 不会为您执行此操作。此外,如果您需要在 XML 文档中向前查找,则您很不走运。
在事件驱动模型中,如果没有对树的访问权限,某些应用程序根本无法实现。当然,您可以在 SAX 事件中自己构建某种树,但 DOM 允许您避免编写该代码。DOM 是 XML 数据的标准树表示形式。
W3C 正在分阶段(或用他们的术语来说是“级别”)定义文档对象模型。Python API 的映射基本上基于 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
支持的 W3C 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 中的命名空间(第 4 节)中所定义。
- xml.dom.XMLNS_NAMESPACE¶
命名空间声明的命名空间 URI,如 文档对象模型 (DOM) Level 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 的根),其中包含一个具有给定 *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()
方法 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
,而不是此接口的实例。
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)¶
按名称删除属性。请注意,它使用的是本地名称,而不是限定名称。如果没有匹配的属性,则不会引发异常。
- 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
继承自 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
节点创建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 建议和 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 编译器生成的典型代理不太可能工作,并且如果通过 CORBA 访问 DOM 对象,则客户端可能需要包装器对象。虽然这确实需要对 CORBA DOM 客户端进行一些额外的考虑,但有经验的实现者认为从 Python 使用 DOM over CORBA 并不是问题。在所有 DOM 实现中,声明为 readonly
的属性可能不会限制写访问。
在 Python DOM API 中,不需要访问器函数。如果提供,它们应该采用 Python IDL 映射定义的形式,但这些方法被认为是不必要的,因为可以直接从 Python 访问属性。对于 readonly
属性,永远不应该提供“设置”访问器。
IDL 定义没有完全体现 W3C DOM API 的要求,例如某些对象的定义,例如 getElementsByTagName()
的返回值是“活动的”。Python DOM API 不要求实现强制执行此类要求。
注释对象¶
Comment
表示 XML 文档中的注释。它是Node
的子类,但不能有子节点。注释的内容,以字符串形式表示。该属性包含开头
<!-
-
和结尾-
->
之间的所有字符,但不包括它们。