通过 XML Catalog 实现 XML 文件的自动化实时校验

引言

XML Catalog 实现了根据 XSD 实时校验 XML 文件的功能。用户不用编写程序,通过少量的配置就可以在编辑 XML 文件的时候得到及时的反馈(需要在 XML 编辑器进行文件的编写),实现了实时的校验。

然而在实际应用中,由于环境的不同以及 XML 文件本身的不同,手动方式的配置并不能满足需求。比如,作者在实践中发现,在开发环境里手动配置的 XML Catalog 是不能保存在运行环境的。而且,许多实际的 XML 的编写方式并没有采用标准的格式,这也给 XML Catalog 的使用带来了很多的不便。

本文针对以上问题,通过例子来说明如何通过扩展 XML Catalog 来实现基于 xsd 对 XML 文件的自动化实时校验。

回页首

XML Catalog 介绍

XML Catalog 是基于 OASIS XML Catalog specification 标准的实现,它提出了一些关于 XML 文件如何引用外部资源的控制。Eclipse 的 WTP 提供了 XML Catalog 的功能,实现利用 schema 对 xml 文件的实时校验功能。XML Catalog 是由来自一个或者多个 catalog 条目文件的条目组成的 xml 文件,其保存了要校验的 xml 文件以及该文件对应的 xsd 文件的映射,在运行时可以自动将它们关联起来,从而实现对 xml 文件的校验。

下面通过一个例子来说明 XML catalog 的相关概念。

XML Catalog 相关概念介绍

 <?xml version="1.0"?> 
 <!DOCTYPE catalog 
 PUBLIC "-//OASIS/DTD Entity Resolution XML Catalog V1.0//EN"
 "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd"> 1 
 <catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog"> 2 
 <group prefer="public" xml:base="file:///usr/share/xml/" > 3 
 <public 
 publicId="-//OASIS//DTD DocBook XML V4.5//EN" 4 
 uri="docbook45/docbookx.dtd"/> 
 <system 
 systemId="http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" 5 
 uri="docbook45/docbookx.dtd"/> 
 <system 
 systemId="docbook4.5.dtd" 6 
 uri="docbook45/docbookx.dtd"/> 
 </group> 
 </catalog>
  1. DOCTYPE 表示这个文件是 OASIS XML catalog 文件。如果没有 Internet 连接,那么,整个 DOCTYPE 的声明需要删除或者注释掉。因为 catalog 处理器会尝试从网络去下载 catalog.dtd 文件,显然在没有网络的环境下,处理器因为找不到文件会报错。
  2. catalog 元素包含了 catalog 的内容和 catalog 的命名空间标识。
  3. group 元素是一个包装元素,可以设置在这个组里面包含的所有 catalog 条目的属性。属性 prefer="public" 指出 catalog resolver(解析器) 在使用 SYSTEM 标识符之前优先使用 PUBLIC 标识符。属性 xml:base 表明,所有 URI 都是相对这个路径。本例中,uri="docbook45/docbookx.dtd"/ 是个相对路径,绝对路径应该是 file:///usr/share/xml/ docbook45/docbookx.dtd "。
  4. public 元素将 publicId 映射到 uri 的路径。publicId 是资源的一个唯一标识,通常是该文件的命名空间 .
  5. system 元素将 systemId 映射到 uri 的路径。systemId 与 publicId 一样,也是资源的唯一标识,通常是资源文件在文件系统的全路径。

XML Catalog 原理

XML Catalog 提供了一种重新定位资源的机制,可以将 xml 引用的 artifacts,包括 URI 地址以及 namespace 名重新定位到另一个地址。通常这种机制被用来将远程的引用资源重定位到本地或者 web。XML catalog 就是一个描述外部实体引用和本地缓存的相同实体的映射的文件。

在实际的开发生产中,xml 文件经常会引用外部的文件,这些文件通常通过 URI 表示,其中以 URL 应用最广。但是如果是绝对的 URL, 那么只有当你的网络能够访问它时才能起作用,如果网络出现问题,那么将不能访问。当是相对 URL 时,例如"../../xml/dtd/docbookx.xml",只有当你的文件系统和定义者一致的时候才能起作用。

一种解决办法就是通过实体解析器(Entity Resolver)或者是 URI 解析器 (URI Resolver ),解析器可以通过检查资源的 URI 来定位资源。 用户通过配置 xml catalog, 手动的指定 xml 文件引用的 xsd 文件的本地地址,URI 解析器通过 xml catalog 里面的映射,找到对应的 xsd, 最后 xml catalog 处理器通过解析器找到的 xsd 对 xml 进行校验。

通俗点说,XML catalog 通过命名空间将 xml 文件及其对应的 xsd 文件联系起来,并通过解析器定位 xsd 文件的位置,最后通过处理器进行校验。

与 javax.xml.validation 通过 xsd 对 xml 进行校验的方法不同,xml catalog 可以通过 Namespace 来校验所有引用这个 xsd 的 xml 文件,从而达到批量校验的效果。例如,a.xml,b.xml,c.xml 都是由 d.xsd 校验,那么只要将 d.xsd 的命名空间配置好,通过该命名空间就可以校验以上三个文件了。

手动方式配置 XML Catalog

手动配置 XML Catalog 比较简单也比较容易理解,可以在 Eclipse 的开发环境中直接进行。选择 File -> New -> Other -> Examples -> Editing and Validating XML files,便可以进行配置了。如下图所示:

图 1. 打开 XML Catalog 的配置界面

图 1. 打开 XML Catalog 的配置界面

从图 1 中可以看到有两种 xml catalog entity , 用户定义的实体及插件的实体。用手动方式生成的配置属于用户配置的实体。

图 2. 新建一个 XML Catalog Entry

图 2. 新建一个 XML Catalog Entry

新建一个 XML Catalog Entry 中的 Location 指明了 xsd 文件的位置,在这里我们选择来源于工作空间。

图 3. 从工作空间选择 student.xsd 文件

图 3. 从工作空间选择 student.xsd 文件

选择 OK 以后,XML Catalog Entry 就创建完成了。XML Catalog 会自动填写其他两个属性,如下图所示。

图 4. 完整的 XML Catalog Entry

图 4. 完整的 XML Catalog Entry

如图所示,Location 标签指定了 xsd 的位置,在这里是工作空间的相对路径;Key Type 标签表明了在这里我们使用的是命名空间的名字作为 xml 和 xsd 的关联;Key 标签的值是 xml 命名空间的值。

图 5. 完整的 XML Catalog Entry

图 5. 完整的 XML Catalog Entry

从图 5 中可以看出,新建的 XML Catalog Entry 已经在 User Specified Entries 目录下。图 1 到 4 显示了 XML Catalog 的手动配置步骤。下面,我们在 XML 编辑器里打开一个 xml 文件,看一下 XML Catalog 的功能。

图 6. 正确的 XML 文件

图 6. 正确的 XML 文件

首先,用 XML 编辑器打开 sample.xml 文件。

图 7. XML Catalog 的实时校验结果

图 7. XML Catalog 的实时校验结果

将 name 为 BB 的学生的 age 标签去调,从图中可以看到在编辑器的右边有一个红色的点,同时在 student 元素下面有个红色的波浪线,提示 student 元素有错误。这是,将鼠标移到 student 元素上,可以看到具体的提示信息,student 元素不完整,缺少 age 元素。

可以看出,应用 XML Catalog 对 xml 文件进行实时校验,配置步骤比较简单,只需提供相应的 xsd 文件及位置,就能将他们关联起来,实现自动的校验。

回页首

扩展 XML Catalog Contributions

在实践中发现,如果通过上一节介绍的手动方式在 Eclipse 开发环境配置 xml catalog,那么这些配置并不会在运行环境生效。然而通常情况下,我们需要的是运行环境的配置。比如我们要开发一些小工具,可以让用户编辑 xml 文件,同时我们内置了一些 xsd 文件来校验用户编辑的 xml 文件是不是正确。因为不能让用户在使用产品的时候再重新配置(因为对用户来说,他们并不需要知道这些 xsd 的存在,还有就是,不能增加用户的负担)。所以,我们需要在开发环境配置好 xsd 的信息,并让这些配置在运行时生效。通过调研,我们发现,如果要在运行环境中直接使用开发环境的配置,那么需要扩展 xml catalog Contributions 这个扩展点。

下面我们就一步步的演示如何在 Eclipse 插件里扩展 XML Catalog Contributions 扩展点。

1.打开 plugin.xml 文件的 Extensions 标签,点击 Add 按钮,添加扩展点。

图 8. 添加扩展点

图 8. 添加扩展点

2.在 Extension Point filter 文本框里输入扩展点的名字,org.eclipse.wst.xml.core.catalogContributions,并选中该扩展点,点击 OK 按钮。

图 9. 选中扩展点

图 9. 选中扩展点

图 10 展示了成功添加扩展点后的 Extension 页面。

图 10. 成功添加扩展点

图 10. 成功添加扩展点

3.新建一个 catalogContribution

图 11. 新建 catalogContribution

图 11. 新建 catalogContribution

4.新建一个 public

图 12. 新建 public

图 12. 新建 public

5.填写 public 的属性信息。public 有两个属性,publicId 和 uri。

publicId 就是命名空间(namespace),uri 就是 xsd 文件的物理位置,可以通过 Browse 按钮来选择 xsd 文件。

图 13. 填写 public 详细信息

图 13. 填写 public 详细信息

通过以上 5 步,就完成了对 xml catalog Contributions 的扩展。图 14 就是完成以上配置以后的 plug.xml 文件内容。从这个文件我们可以清楚地看清楚扩展的相应配置。

图 14. plugin.xml 文件

图 14. plugin.xml 文件

从图 15 可以看出,与手工方式的配置不同,在运行时的环境里,User Specified Entries 里面并没有内容。

图 15. 运行环境的 XML Catalog 配置

图 15. 运行环境的 XML Catalog 配置

将 sample.xml 改错,可以看见 XML Catalog 的提示信息。

图 16. sampe.xml 文件

图 16. sampe.xml 文件

通过以上的步骤,我们演示了,如何扩展 XML Catalog。在下一个部分,我们将会演示如何扩展 URI Resolver 实现特殊 XML 文件的校验。

回页首

扩展 URI Resolver

XML Catalog 虽然提供了比较强大的功能,但是由于实际生产环境的复杂性,一些 xml 文件并不能由其进行校验。比如,有些 xml 文件,由于书写不规范,并没有命名空间,还有些 xml 文件,由于应用环境的原因,其使用了 xsi:schemaLocation 元素,将引用的 xsd 文件直接定位到了虚拟的路径,导致 xml catalog 的定位功能失效 . 对于第一种情况,由于 XML Catalog 的设计理念就是通过命名空间进行 xml 和 xsd 的关联,所以,不支持此种情况。对于第二中情况,我们可以通过扩展 XML Catalog 来实现。

在扩展 URI Resolver 之前,我们对 XML Catalog 可以处理的 xml 和 xsd 的类型进行了分类,以便大家能够清楚地知道 XML Catalog 可以解决哪些问题。

xsd \ xml 有命名空间 无命名空间
有命名空间,无 xsi:schemaLocation 可以 不可以
有命名空间,有 xsi:schemaLocation,且其值是 xsd 实际存在的位置 可以 不可以
有命名空间,有 xsi:schemaLocation,且其值不是 xsd 实际存在的位置 可以 不可以
无命名空间  不可以 不可以

URI Resolver 简介

URIResolver 负责资源的定位,XML Catalog 的处理器根据 URIResolver 的资源位置找到相应的 xsd,然后进行校验。

特殊的 XML 文件

如图 18 所示,sample.xml 文件里中有一个 xsi:shemaLocation 属性,它将 xsd 的位置定位到 http://www.sample.com/sample/schemas/student.xsd。正常情况下,XML Catalog 会到该位置去找 xsd, 然而,在本文中这是一个无效的地址,所以 XML Catalog 会因为找不到 xsd 而不起作用。

图 18. 带有 schemaLocation 标签的 XML 文件

图 18. 带有 schemaLocation 标签的 XML 文件

扩展 org.eclipse.wst.common.uriresolver.resolverExtensions

resolverExtensions 扩展点可以让用户注册自己的 URI Resolver,从而达到扩展默认 Resolver 的功能的作用。与默认的 Resolver 一样,用户扩展的 Resolver 也可以被编辑器,校验器和向导调用。

图 17. 添加扩展点 resolverExtensions

图 17. 添加扩展点 resolverExtensions

如下图所示,该扩展点有三个属性,class(类名), stage(阶段)和 priority(优先级)。Class 指定了实现 org.eclipse.wst.common.uriresolver.internal.provisional.URIResolver 接口的类;stage 指定了在哪个阶段运行 resolver(解析器),有三个值,分别是 prenormalization, postnormalization 和 physical,默认是 physical。Prenormalization 表示解析器在输入参数的格式统一之前运行,postnormalization 表示解析器在输入参数的格式统一之前运行,physical 表示在所有的 pre 和 postnormalization 解析器之后运行。Priority 指定了在处在相同 stage 的解析器的执行优先级。优先级分为 high(高级),medium(中级)和 low(低级)三种,默认为中级。

图 18. 填写扩展点的属性

图 18. 填写扩展点的属性

下图为增加了 resolverExtensions 扩展点的 plugin.xml 文件的内容。

图 19. plugin.xml 文件内容

图 19. plugin.xml 文件内容

实现 URIResolverExtension

1.首先,在插件中新建一个类,实现 URIResolverExtension 接口。URIResolverExtension 接口提供了 resolve 方法,用来重新定位 xsd 资源,也就是找到有效的 xsd。该方法的参数有四个,第一个类型为 IFile,是在工作空间 (workspace) 中的文件,第二个参数是 String baseloaction,它是该文件在文件系统的绝对路径,第三个参数是 publicId,它是该文件的命名空间,最后一个参数是 String systemid,它是文件的实际路径,对于 xml 文件来说,它的 systeid 为空。但是因为我们在第 2 小节扩展了 XML Catalog, 所以,对于在 XML Catalog 文件里面配置好的 publicId,它的 systemId 就是该文件里面 Uri 的值,也就是 xsd 文件的实际路径。该函数的返回值就是 xml 文件引用的 xsd 文件的位置。

清单 1. 实现 URIResolverExtension 接口
 public class MyURIResolverExtension implements URIResolverExtension { 

 public MyURIResolverExtension() { 
 } 

 @Override 
 public String resolve(IFile file, String baseLocation, String publicId, 
 String systemId) { 
 return null; 
 } 

 }
清单 2. 添加 catalog 到 catalog manager
		ICatalog catalog = XMLCorePlugin.getDefault().getDefaultXMLCatalog();
if (catalog == null) {
			return null;
	 }
清单 3. 重新定位资源
 if (myResolved == null) { 
 if (publicId != null) { 
 if ((systemId != null && systemId.endsWith("student.xsd"))) //$NON-NLS-1$ 
 { 
 try { 
 int index = systemId.lastIndexOf("/"); 
 if (index > -1) 
 
				 systemId = systemId.substring(index); 
 myResolved = catalog.resolvePublic(publicId, systemId); 
 } catch (MalformedURLException me) { 
 myResolved = null; 
 } catch (IOException ie) { 
 myResolved = null; 
 } 
 } 
 } 
 }

由清单 3 可以看出,我们通过 catalog manager 的 resolvePublic 方法,通过 publicId 找到 Catalog 里与 publicId 对应 uri 的值,这个值就是 xsd 文件的路径。

回页首

小结

本文首先介绍了 XML Catalog 相关概念以及基本原理,使读者对其有了初步的认识。接着通过一个简单的例子介绍了手动方式配置 XML Catalog 的步骤,使读者有了进一步的了解。最后,通过扩展 XML Catalog 和 URI Resolver 两个扩展点来实现比较高级的功能,使读者对该技术有了深入的了解。XML Catalog 是比较通用的解决 XML 实时校验问题的方法,尤其与 XML Catalog 和 URI Resolver 两个扩展点的结合在解决一些特殊的 XML 文件的实时校验问题时,往往能取得事半功倍的效果。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享