该教程是针对JDK 8编写的。本页面中描述的示例和实践不利用后续版本引入的改进,并且可能使用不再可用的技术。
请参阅Java语言变化以了解Java SE 9及其后续版本中更新的语言功能的概要。
请参阅JDK发行说明以获取有关所有JDK版本的新功能、增强功能和已删除或弃用选项的信息。
文档对象模型(DOM)标准首先是为文档(例如文章和书籍)设计的。此外,JAXP 1.4.2实现还支持XML Schema,这对于任何应用程序都可能是一个重要的考虑因素。
另一方面,如果你处理的是简单的数据结构,并且XML Schema在你的计划中不是很重要的一部分,那么你可能会发现更适合你目的的是更多面向对象的标准之一,例如JDOM或dom4j。
从一开始,DOM就被设计为语言中立。由于它是为像C和Perl这样的语言设计的,DOM不利用Java的面向对象特性。这个事实,加上文档和数据之间的区别,也有助于解释DOM处理与JDOM或dom4j结构处理不同的方式。
在本节中,我们将检查这些标准底层模型之间的差异,以帮助您选择最适合您应用程序的模型。
DOM中使用的文档模型与JDOM或dom4j中使用的数据模型之间的主要区别在于:
在编程这两个模型时,节点在数据层次结构中的构成方式的不同是造成差异的主要原因。然而,对混合内容的支持能力,比任何其他因素都更能解释标准定义节点的方式的差异。因此,我们首先来研究DOM的混合内容模型。
在DOM层次结构中,文本和元素可以自由混合。这种结构在DOM模型中被称为混合内容。
混合内容在文档中经常出现。例如,假设你想要表示这个结构:
<sentence>这是一个<bold>重要</bold>的想法。</sentence>
DOM节点的层次结构看起来可能是这样的,每一行代表一个节点:
ELEMENT: sentence + TEXT: 这是一个 + ELEMENT: bold + TEXT: 重要 + TEXT: 的想法.
请注意,sentence元素包含文本,然后是一个子元素,然后是其他文本。混合文本和元素定义了混合内容模型。
为了提供混合内容的能力,DOM节点本质上非常简单。在上面的例子中,第一个元素的“内容”(其值)仅仅标识了它是什么类型的节点。
首次使用DOM的用户通常会对这个事实感到困惑。在导航到<sentence>节点之后,他们会询问节点的“内容”,并期望得到一些有用的东西。相反,他们只能找到元素的名称sentence。
注意 - DOM节点API定义了nodeValue()、nodeType()和nodeName()方法。对于第一个元素节点,nodeName()返回sentence,而nodeValue()返回null。对于第一个文本节点,nodeName()返回#text,nodeValue()返回“This is an ”。重要的是,元素的值与其内容不同。
在上面的示例中,询问句子的“文本”是什么意思?根据您的应用程序,以下任何一种都可以合理:
使用DOM,您可以自由地创建所需的语义。但是,您还需要进行必要的处理以实现这些语义。而像JDOM和dom4j这样的标准则使得处理简单的事情更容易,因为层次结构中的每个节点都是一个对象。
虽然JDOM和dom4j允许元素具有混合内容,但它们的主要设计目标不是处理这种情况。相反,它们的目标是用于包含数据的XML结构的应用程序。
数据结构中的元素通常只包含文本或其他元素,而不是两者兼有。例如,这是一些表示简单通讯录的XML:
<addressbook> <entry> <name>Fred</name> <email>fred@home</email> </entry> ... </addressbook>
注意 - 对于像这样的非常简单的XML数据结构,您还可以使用Java平台版本1.4中内置的正则表达式包(java.util.regex)。
在JDOM和dom4j中,当您导航到包含文本的元素时,您调用诸如text()的方法来获取其内容。但是,在处理DOM时,您必须检查子元素列表以“组合”节点的文本,就像之前看到的那样 - 即使该列表只包含一个项(TEXT节点)。
因此,对于像通讯录这样的简单数据结构,使用JDOM或dom4j可以节省一些工作。即使数据在技术上是“混合的”,但如果对于给定节点始终存在且仅存在一个文本段落,则使用其中一种模型可能是有意义的。
这是一个这种类型结构的示例,在JDOM或dom4j中也可以轻松处理:
<addressbook> <entry>Fred <email>fred@home</email> </entry> ... </addressbook>
在这里,每个条目都有一小段标识文本,后面跟着其他元素。使用这种结构,程序可以导航到一个条目,调用text()来找出它属于谁,并在正确的节点上处理<email>子元素。
但是,为了您能够充分了解在搜索或操作DOM时需要进行的处理,了解DOM可能包含的节点类型是很重要的。
这是一个说明这一点的示例。它是表示以下数据的表示:
<sentence> The &projectName; <![CDATA[<i>project</i>]]> is <?editor: red><bold>important</bold><?editor: normal>. </sentence>
这个句子包含一个实体引用 - 指向在其他地方定义的实体的指针。在这种情况下,实体包含项目的名称。该示例还包含一个CDATA节(未解释的数据,如HTML中的<pre>数据)以及处理指令(<?...?>),这种情况下告诉编辑器在呈现文本时使用的颜色。
这是该数据的DOM结构。它代表了一个强大应用程序应该准备处理的结构类型:
+ ELEMENT: sentence + TEXT: The + ENTITY REF: projectName + COMMENT: The latest name we are using + TEXT: Eagle + CDATA: <i>project</i> + TEXT: is + PI: editor: red + ELEMENT: bold + TEXT: important + PI: editor: normal
这个示例描述了DOM中可能出现的节点类型。虽然您的应用程序大部分时间可能会忽略它们,但一个真正强大的实现需要识别并处理每个节点。
同样,导航到节点的过程涉及处理子元素,忽略您不感兴趣的元素并检查您感兴趣的元素,直到找到您感兴趣的节点。
一个在固定、内部生成的数据上工作的程序可以承担简化的假设:处理指令、注释、CDATA节点和实体引用在数据结构中不存在。但是,对来自外部世界的各种数据(特别是数据)进行处理的真正强大的应用程序必须准备处理所有可能的XML实体。
(一个“简单”的应用程序只能在输入数据包含它所期望的简化的XML结构时工作。但没有验证机制来确保更复杂的结构不存在。毕竟,XML的设计目的就是允许它们存在。)
为了更加强大,DOM应用程序必须执行以下操作:
当然,许多应用程序不必担心这些问题,因为它们所见到的数据将受到严格控制。但是,如果数据可以来自各种外部来源,那么应用程序可能需要考虑这些可能性。
您需要执行这些功能的代码在本课程的末尾给出,搜索节点和获取节点内容。目前,我们只需要确定DOM是否适合您的应用程序。
正如您所看到的,当您使用DOM时,即使是从节点获取文本这样简单的操作也需要一些编程。因此,如果您的程序处理简单的数据结构,那么JDOM、dom4j甚至1.4正则表达式包(java.util.regex)可能更适合您的需求。
然而,对于完整的文档和复杂的应用程序,DOM为您提供了很大的灵活性。如果您需要使用XML Schema,那么DOM仍然是最佳选择 - 至少目前是这样。
如果您在开发的应用程序中同时处理文档和数据,那么DOM可能仍然是您最好的选择。毕竟,一旦您编写了用于检查和处理DOM结构的代码,就很容易为特定目的进行定制。因此,选择在DOM中执行所有操作意味着您只需要处理一组API,而不是两组。
此外,DOM标准是一种内存中文档模型的标准化标准。它功能强大且稳定,并且有许多实现。这对于许多大型安装来说是一个重要的决策因素,特别是对于需要最小化由于API更改而产生的成本的大规模应用程序。
最后,即使通讯录中的文本今天不允许加粗、斜体、颜色和字体大小,将来您可能会想要处理这些内容。由于DOM可以处理几乎任何您提供的内容,选择DOM可以更轻松地为您的应用程序提供未来的支持。