在 第 1 部分中,我们向您展示了在处理节点时可以使用的一组 DOM Level 3 Core 特性。现在我们将描述从 DOM 数据模型到 XMLInfoset 的映射,以及如何利用所谓的 DOM bootstrapping mechanism (DOM 自举机制)来消除应用程序中依赖于实现的代码。之后我们将展示如何重新验证内存中的 DOM 以检查它是否仍然符合您的模式,我们还将描述如何访问元素和属性类型信息,最后展示如何在 Xerces 中使用所有这些好的特性。
为 DOM Level 3 而完成的一项重要任务是:通过加入新的可以查询缺少的 XMLInfoset 信息的方法,使 DOM 数据模型与 XML
Information Set(Infoset)相匹配。例如,现在可以通过
Document 接口(它被映射到 Infoset
文档信息项)查询和修改储存在一个 XML 声明中的信息,例如
version 、
standalone
和
encoding 。类似地,基本 URI 和声明基本 URI 属性是根据 XML Base 处理的,它们被放在
Node 接口中。您还可以获取 XML Infoset 元素内容的 whitespace 属性。这个属性表明一个
Text
节点是否只包含可以被忽略的空白。可以通过
Text
接口(它映射到 XML Inforset 字符信息项)获得这个属性。清单1展示了在 Java 语言绑定中这个接口中的实际方法签名。
清单1. 在 Java 语言绑定的方法签名
// XML Declaration information on
// the org.w3c.dom.Document interface
public String getXmlEncoding();
public void setXmlEncoding(String xmlEncoding);
public boolean getXmlStandalone();
public void setXmlStandalone(boolean xmlStandalone)
throws DOMException;
public String getXmlVersion();
public void setXmlVersion(String xmlVersion)
throws DOMException;
// element content whitespace property on the Text
// interface
public boolean isWhitespaceInElementContent();
|
通过
Attr
接口的
schemaTypeInfo
属性,您还可以获取一个属性信息项的属性类型特性的值 ——即一个属性的类型。
后面有一节对此给予了更详细的介绍。
此外,这里提供了一个新的特性,用于以最接近 XML Infoset 的形式返回
Document ,在此之前,由于不同的编辑操作(例如插入或者删除节点)的作用,文档通常会更加偏离
XML Infoset。这是在进行
文档标准化(
document
normalization
)操作时可能造成的部分结果,我们将在下面的
文档标准化一节中对此加以描述。
最后,新的 Appendix C 提供了 XML Infoset 模型与 DOM
之间的映射,在这种映射中,每一个 XML Infoset 信息项都映射到其相应的
Node ,反之也一样,一个信息项的每一个属性都映射到其相应
Node
的属性。这个附录应该可以使您对 DOM
数据模型有一个很好的全面了解,并且展示了如何访问所要查找的信息。
以前版本的 DOM 规范没有提供任何自举 DOM 实现的方法。因此,在应用程序中,必须首先使用与具体实现相关的代码。DOM Level 3
Core 规范定义了一个
DOMImplementationRegistry
对象,通过它可以按照所需的功能集找到合适的实现。例如,您可以要求得到一个支持
mutation 事件的实现。清单 2 显示了如何在应用程序中使用自举机制找到合适的实现。
清单2. 使用自举机制找到实现
// set DOMImplementationRegistry.PROPERTY property
// to reference all known DOM implementations
System.setProperty(DOMImplementationRegistry.PROPERTY,
"org.apache.xerces.dom.DOMImplementationSourceImpl");
// get an instance of DOMImplementationRegistry
DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
// DOM implementation that support the specified features
DOMImplementation i = registry.getDOMImplementation("MutationEvent");
|
这样做有诸多好处。它不但使您的代码与实现无关,而且还允许 DOM 实现器提供更适合您需求的实现。这样可以使您的应用程序具有更好的性能。例如,Xerces 有多种实现:一种是全功能的,支持 DOM 的许多可选模块;另一种是最小化的,只支持核心功能,提供较轻型的对象。如果不需要支持 mutation 事件,那么何必为创建支持这种功能的对象而付出代价呢?通过使用机制机制,就可以使用对于应用程序最合适的实现。
在 DOM Level 3 中定义的一个新方法是
Document
接口的
normalizeDocument
方法。从方法名可以看出,您可以使用这个方法来标准化文档。在默认情况下,这个方法完成以下工作:
- 标准化
Text节点,将相邻的Text节点整合为一个Text节点。 - 根据
EntityReference节点所引用的实体更新它们的内容。 - 验证和修复文档中的命名空间信息,使命名空间格式是格式良好的。
一定要注意,在这个方法中使用的命名空间标准化算法(在 Appendix B 中定义)只对
namespace-aware
节点起作用,这些节点是使用具有“NS”后缀的方法(例如
createElementNS )创建的。
Namespace
unaware 节点,即用 DOM Level 1 方法(如
createElement )创建的节点,与所有依赖于
XML 命名空间的处理不完全兼容。如果在文档中有 DOM Level 1 节点,那么在尝试进行命名空间标准化时,
normalizeDocument
会失败并报告一个错误。一般来说,如果希望使用 XML 命名空间,并且要对文档执行任何需要 XML 命名空间支持的操作,那么就不应该用
DOM Level 1 方法创建节点。对于其他的操作,例如针对 XML Schema 重新验证内存中的文档,也是如此。
还可以通过
DOMConfiguration 配置
normalizeDocument ,以便对文档执行其他操作。例如,可以使用这个方法去掉注释,将
CDATASection
节点转换为
Text
节点,或者放弃树中所有命名空间声明属性。还可以通过它一次完成上述所有工作,从而轻松地使文档具有可以自然地映射到
XML
Infoset 的形式。清单3展示了如何用
Document.config
控制
normalizeDocument 。
清单3. 使用 Document.config 控制 normalizeDocument
// retrieve document configuration
DOMConfiguration config = document.getConfig();
// remove comments from
config.setParameter("comments", false);
// remove namespace declarations
config.setParameter("namespace-declarations", false);
// transform document
core.normalizeDocument();
// put document into a form closest to the XML Infoset
config.setParameter("infoset", true);
// transform document
core.normalizeDocument();
|
normalizeDocument
方法还允许您用 XML Schema 或者
DTD
对内存中的文档进行重新验证。过去,要在文档修改后对它进行重新验证,必须将它保存为一个文件,再用验证解析器读回去。有了这种新方法,现在就可以通过让
DOM
实现重新验证内存中的文档从而更有效地完成这项工作。为此,首先需要将
DOMConfiguration
的
validate
参数设置为
true 。然后需要实现一个
DOMErrorHandler
对象,验证错误将报告给这个对象,再用
error-handler
参数将这个对象注册到
Document
上。这与对 SAX 解析器所做的工作很类似。最后,可以通过调用
normalizeDocument
检查文档是否有效。在本文的后面,我们展示了如何用
Xerces
完成这项工作。
目前,还没有访问 XML Schema Post-Schema Validation Infoset(PSVI)的标准 API。不过,DOM Level
3 允许您获取一些 PSVI 信息。例如,如果希望获得 PSVI 标准化的模式值属性,那么就将
DOMConfiguration
上的
datatype-normalization
和
validate
参数设为“true”,并用经过 XML Schema 标准化的值调用
normalizeDocument
以更新树 ——这意味着文档中属性值和元素内容现在表示的是 PSVI 标准化的模式值属性。
前一版本的 DOM
没有提供对任何类型信息的任何访问途径,没有任何办法可以得到文档中一个属性或者元素节点的类型。正如我们在前面提到的,在
DOM Level
3 Core 中现在已经可以做到这一点了,这要归功于引入了名为
TypeInfo
的新接口。这个接口代表一个类型定义,由名称和命名空间
URI
成对组成。视验证文档时所用的模式而定,这种类型定义所对应的内容可能是不同的。
如果使用 DTD (在装载的时候,或者使用
normalizeDocument ),那么一个属性节点的
TypeInfo
表示这个属性的类型。在 XML
Infoset
中这是属性信息项的属性类型属性。不过,对于元素节点,
TypeInfo
的名称为
null ,命名空间 URI 为
null ,这是因为
DTD 没有定义元素类型。
现在,如果使用 XML Schema 验证文档,那么
TypeInfo
在元素节点上表示元素类型,而在属性节点上表示属性类型。事实上,
TypeInfo
还表示相应元素和属性信息项的 PSVI 类型定义属性。
注意,要使这些信息可用,必须根据所使用的模式验证元素或者属性的有效性。如果验证失败,那么应该让 DOM 实现提供经过声明的类型以帮助您相应地修正文档。而且,如果类型是匿名的,那么就返回一个特定于实现的惟一名。
Apache Xerces2 parser 2.4.0 提供了 DOM Level 3 Core
的一个早期实现。不过,因为 DOM Level 3 Core 规范还不是 W3C
建议,所以这个实现不是 Xerces
默认发布的一部分。要使用这个功能,需要通过类型覆盖变为
Xerces
DOM 实现类(例如
org.apache.xerces.dom.DocumentImpl ),或者用“
jars-dom3 ”目标在本地编译
Xerces。这会生成包含
DOM
Level 3 API 的
om3-xml-apis.jar
文件和包含
API 实现的
dom3-xercesImpl.jar
文件。要编译 Xerces,需要从
CVS 中提取源代码,或者下载发布的 Xerces 源代码和工具。
利用 DOM Level 3 支持编译好 Xerces 之后,将新生成的 jar 文件
(
dom3-xml-apis.jar 和
dom3-xercesImpl.jar )加入到
CLASSPATH 中,就可以开始使用 DOM
Level 3 进行编程了。
如果只需要一个 DOM Level 3 Core 实现,那么您需要通过使用
自举机制
请求获得支持“
Core ”或者“
XML ”的 Xerces 实现。正如我们所提到的,这样做将返回一个使用更少内存的DOM
实现,但是该实现不提供对可选模块(如遍历)的支持。
我们还提到过,DOM Level 3
引入了一种机制,利用这种机制可以对内存中的文档进行重新验证。不过,当前版本的
Xerces (2.4.0) 只支持针对 XML
Schema、而不是针对 DTD 的重新验证。注意,如果一个 DOM
实现同时支持针对 XML Schema 和 DTD
的重新验证,并且文档引用了不同的模式(例如一个 DTD 和一个
XML Schema),那么就会不明确应该使用哪一种模式进行重新验证。为明确这一点,例如,希望针对
XML Schema 进行重新验证,可以通过获取
Document
节点的子节点然后删除
DocumentType
子节点来从文档中删除
DocumentType
节点,或者设置
DOMConfiguration
的
schema-type
参数。可以通过两种方法将一个 XML 模式与一个文档相关联:
- 向
documentElement(根元素)添加一个名为xsi:schemaLocation或者xsi:noSchemaLocation的属性,其值为模式的位置。 - 设置
DOMConfigurationschema-location参数,使它的值为在重新验证要使用的模式的位置。
注意,应该用绝对 URI 指定模式位置。如果您决定使用相对URI,那么它将被解析为与通过
Document 接口的
documentURI
属性公开的文档的位置相对的位置。或者,可以实现并注册一个
DOMEntityResolver (在
DOM Level 3 Load and Save 规范中定义),自己解析相对 URI。清单 4 展示了如何重新验证内存中的文档:
清单4. 在内存中重新验证 文档
// Retrieve configuration
DOMConfiguration config = document.getConfig();
// Set document base URI
document.setDocumentURI("file:///c:/data");
// Configure the normalizeDocument operation
config.setParameter("schema-type", "http://www.w3.org/2001/XMLSchema");
config.setParameter("validate", true);
config.setParameter("schema-location", "personal.xsd");
// Revalidate your document in memory
document.normalizeDocument();
|
我们向您展示了 DOM Level 3 Core 带来的新特性如何使您免于编写大量代码,以及如何提高应用程序的性能。编写的代码越少,维护工作就越少,所产生的错误也就越少,这样您的工作就越是得心应手!我们还展示并解释了如何使用几个强大的新特性,例如内存中的重新验证以及对类型信息的访问 —— 这些都是开发人员长期以来梦寐以求的特性。
简言之,DOM Level 3 Core 将使您的生活更加轻松,如果与像 DOM Load & Save 这样的其他模块结合使用,则效果更佳。我们希望本文可以帮助您好好利用它。
- 您可以参阅本文在 developerWorks 全球站点上的
英文原文.
- 本系列的
第
1 部分讨论了对节点的操作,例如重命名,将节点从一个文档移到另一个文档,设置文本内容等等(
developerWorks,2003年8月)。
- 阅读
DOM
Level 2 CoreW3C 推荐标准。
- 阅读
XML
Information Set 规范以便更好地理解 XML Infoset。
- 熟悉最新的
DOM
Level 3 Core
Last Call 草案。
- 在
W3C
的 Technical Reports and Publications 页面 可以找到更多关于其他 W3C 规范的内容,例如
XML Schemas and Namespaces in XML。
- 了解关于
Xerces2
DOM 实现的内容。
- 下载最新的
Xerces-J
解析器。
- 在
developerWorks
XML 专区
中可以找到更多的 XML 资源,包括入门教程
理解
DOM(
developerWorks,2003年7月)。
- 要了解更多关于使用 DOM 进行自举的内容,参阅 Brett McLaughlin 撰写的技巧系列:
- 第 1 部分解释了自举是什么,探索了与之相关的一些问题,并给出了在 DOM Levels 1 和 2 中使用自举的基础知识( developerWorks,2002年11月)。
- 第 2 部分在第一部分的基础上,展示了在 DOM 应用程序中更好的自举方式( developerWorks,2002年12月)。
- 第 3 部分解释了 DOM Level 3 中与自举有关的修改,以及它们如何对 DOM Levels 1 和 2 进行改进( developerWorks,2002年12月)。
- 访问
developerWorks
上颇有人气的、由 Brett McLaughlin 主持的
XML
和 Java 技术论坛,这是一个开放的、名声很好的环境,在这里可以讨论与 XML 和 Java 相关的所有内容。
- 研究
IBM
WebSphere Studio Site Developer,这是一个健壮的、易于使用的开发环境,可用于创建、编译和维护动态
Web 站点、应用程序以及 Web 服务。
- 看看如何成为
IBM
认证的 XML 和相关技术的开发人员。
Arnaud Le Hors 是 IMB 的高级软件工程师,也是 XML Standards Strategy Group 的成员。他在各种 W3C 工作组中担任 IBM 的代表,例如 XML Core 和 DOM。他是 DOM Level 1、2 和 3 以及核心规范(Core Specification)的编辑之一。 Arnaud 还参与了 Xerces 的开发,同时也是 Xerces2 的设计者之一。可以通过 lehors@us.ibm.com与他联系。