文档对象模型(Document Object Model,DOM)是公认的 W3C 标准,它被用于与平台及语言无关的 XML 文档内容、结构和样式的动态访问和更新。它为表示文档定义了一套标准的接口集,也为访问和操纵文档定义了一套标准的方法。DOM 得到广泛的支持和普及,并且它以各种不同的语言实现,包括 Java、Perl、C、C++、VB、Tcl 和 Python.
正如我将在本文所演示的,当基于流的模型(例如 SAX)不能满足 XML 处理要求时,DOM 是一个极佳的选择。不幸的是,规范的几个方面,例如其语言无关性接口和“一切都是节点(everything-is-a-node)”抽象概念的使用,使其难以使用且易于生成脆弱代码。这在最近的几个大型 DOM 项目的研究中尤其明显,这些项目是由许多开发人员过去一年所创建的。下面讨论了常见的问题及其补救措施。
文档对象模型
DOM 规范被设计成可与任何编程语言一起使用。因此,它尝试使用在所有语言中都可用的一组通用的、核心的功能部件。DOM 规范同样尝试保持其接口定义方面的无关性。这就允许 Java 程序员在使用 Visual Basic 或 Perl 时应用他们的 DOM 知识,反之亦然。
该规范同样将文档的每个部分看成由类型和值组成的节点。这为处理文档的所有方面提供了完美的概念性框架。例如,下面的 XML 片段
the Italicized portion. |
就是通过以下的 DOM 结构表示的:
图 1:XML 文档的 DOM 表示
树的每个Document 、 Element 、 Text 和 Attr 部分都是 DOM Node 。
完美的抽象确实付出了代价。考虑 XML 片段: Value 。您或许会认为文本的值可以通过普通的 Java String 对象来表示,并且通过简单的 getValue 调用可访问。实际上,文本被当成 tagname 节点下的一个或多个子 Node 。因此,为了获取文本值,您需要遍历 tagname 的子节点,将每个值整理成一个字符串。这样做有充分的理由: tagname 可能包含其它嵌入的 XML 元素,在这种情况下获取其文本值没有多大意义。然而,在现实世界中,我们看到由于缺乏便利的函数导致频繁的编码错误占了 80% 的情况,这样做的确有意义。
设计问题
DOM 语言无关性的缺点是通常在每个编程语言中使用的一整套工作方法和模式不能被使用。例如,不能使用熟悉的 Java new 构造创建新的 Element ,开发者必须使用工厂构造器方法。 Node 的集合被表示成 NodeList ,而不是通常的 List 或 Iterator 对象。这些微小的不便意味着不同寻常的编码实践和增多的代码行,并且它们迫使程序员学习 DOM 的行事方法而不是用直觉的方法。
DOM 使用“一切都是节点”的抽象。这就意味着几乎 XML 文档的每个部分,例如: Document 、 Element 和 Attr ,全都继承( extend ) Node 接口。这不仅是概念上完美,而且还允许每个 DOM 的不同实现通过标准接口使其自身的类可见,并且没有通过中间包装类所导致的性能损失。
由于存在的节点类型数量及其访问方法缺乏一致性,“一切都是节点”的抽象丧失了一些意义。例如, insertData 方法被用来设置 CharacterData 节点的值,而通过使用 setValue 方法来设置 Attr (属性)节点的值。由于对于不同的节点存在不同的接口,模型的一致性和完美性降低了,而学习曲线增加了。