内容


探索 DOM Level 3 Core 的关键特性,第2部分

自举、映射到XML Infoset、访问类型信息以及使用 Xerces

Comments

第 1 部分中,我们向您展示了在处理节点时可以使用的一组 DOM Level 3 Core 特性。现在我们将描述从 DOM 数据模型到 XMLInfoset 的映射,以及如何利用所谓的 DOM bootstrapping mechanism(DOM 自举机制)来消除应用程序中依赖于实现的代码。之后我们将展示如何重新验证内存中的 DOM 以检查它是否仍然符合您的模式,我们还将描述如何访问元素和属性类型信息,最后展示如何在 Xerces 中使用所有这些好的特性。

映射到 Infoset

为 DOM Level 3 而完成的一项重要任务是:通过加入新的可以查询缺少的 XMLInfoset 信息的方法,使 DOM 数据模型与 XML Information Set(Infoset)相匹配。例如,现在可以通过 Document 接口(它被映射到 Infoset 文档信息项)查询和修改储存在一个 XML 声明中的信息,例如 versionstandaloneencoding 。类似地,基本 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 实现重新验证内存中的文档从而更有效地完成这项工作。为此,首先需要将 DOMConfigurationvalidate 参数设置为 true 。然后需要实现一个 DOMErrorHandler 对象,验证错误将报告给这个对象,再用 error-handler 参数将这个对象注册到 Document 上。这与对 SAX 解析器所做的工作很类似。最后,可以通过调用 normalizeDocument 检查文档是否有效。在本文的后面,我们展示了如何用 Xerces完成这项工作。

目前,还没有访问 XML Schema Post-Schema Validation Infoset(PSVI)的标准 API。不过,DOM Level 3 允许您获取一些 PSVI 信息。例如,如果希望获得 PSVI 标准化的模式值属性,那么就将 DOMConfiguration 上的 datatype-normalizationvalidate 参数设为“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 实现提供经过声明的类型以帮助您相应地修正文档。而且,如果类型是匿名的,那么就返回一个特定于实现的惟一名。

在 Xerces2 中使用 DOM Level 3 API

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.jardom3-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 这样的其他模块结合使用,则效果更佳。我们希望本文可以帮助您好好利用它。


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=XML
ArticleID=21159
ArticleTitle=探索 DOM Level 3 Core 的关键特性,第2部分
publish-date=03012003