您的位置:首页 > 其它

使用正确的dtd声明和entityResolver避免saxReader联网验证

2012-12-10 19:19 393 查看

在使用许多使用xml配置文件的框架时,都会碰到以下的问题。有时候项目运行起来,需要花费许多的时间,有时候项目甚至还启动不起来。如使用hibernate时,经常报以下的错误:

这是由于在hibernate中在解析xml时,默认会对所需要解析的xml进行validate,即进行验证,验证所写的xml是否符合声明格式要求。在网上搜索相关的帖子,提出的办法就是禁用掉这个验证。但是hibernate解析xml工作是在它的内部进行的,程序上不能对其进行修改;同时,既然hibernate内部使用了这个验证,即有它验证的需要,仅仅禁用掉这个验证并不能解决实际的问题。

在hibernate3.X版本一直到hibernate3.5版本,在hibernate.xml配置文件中,一直使用的xml声明即是如下:

而是hibernate3.6以上版本,所写的声明中的url地址就变了(当然以前的还继续有效),变成了

这两个声明,在3.6以上版本都是可以接受了。前一声明在3.5及以前版本是正确的。但对于这个声明,如果修改了其中任意一个字符,在启动时都会报错。究其原因,则由于在对xml进行验证时,hibernate提供了一个自己实现的entityResolver。

首先,我们来hibernate是如何加载配置文件的,在类Configuration.doConfigure(InputStream stream, String resourceName)方法中,hibernate首先使用xmlHelper创建一个saxReader,然后使用这个saxReader来取得一个document,最后根据这个document再进行以下的处理。我们来看相应的代码实现:

再看创建saxReader的过程:

取得一个saxReader并设置其验证为true,即要对xml进行结构验证,然后设置其中一个entityResolver,再处理文档。这里的这个entityResolver,就是我们在具体项目中需要使用的一个文档声明解析器。

何为entityResolver,在官方的doc上有如下的说明,现copy如下: 如果 SAX 应用程序需要实现自定义处理外部实体,则必须实现此接口并使用 setEntityResolver 方法向 SAX 驱动器注册一个实例。

这就是说,对于解析一个xml,sax首先读取该xml文档上的声明,根据声明去寻找相应的dtd定义,以便对文档进行一个验证。默认的寻找规则,即通过网络(实现上就是声明的dtd的uri地址)来下载相应的dtd声明,并进行认证。下载的过程是一个漫长的过程,而且当网络中断或不可用时,这里就会报错的,就是因为相应的dtd声明没有被找到的原因。

entityResolver的作用就是项目本身就可以提供一个如何寻找dtd声明的方法,即由程序来实现寻找dtd声明的过程,比如我们将dtd文件放到项目中某处,在实现时直接将此文档读取并返回给sax,即可。这样就避免了通过网络来寻找相应的声明。

首先看entityResolver的接口方法声明:

这里,它接收两个参数publicId和systemId,并返回一个inputSource对象。这里的publicId对应于上面的hibernate.cfg.xml,它就是-//Hibernate/Hibernate Configuration DTD 3.0//EN,而systemId则是http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd。此接口定义为,如果程序实现能够找到本地的一个inputSource实现,即本地的一个dtd,并返回之,则sax就使用此inputSource进行验证解析;否则程序实现返回null,那么sax将执行默认的查找规则,即通过uri地址(即systemId)进行查找了。

那么,我们来看hibernate的entityResolver实现,此实现为类DTDEntityResolver,继续参看其实现:

看其实现,即是首先判断systemId是否以内置的http://hibernate.sourceforge.net/或classpath://开始。前一个对应于常用配置,后一个对应于以classpath方式的配置。只有将systemId以这两个字符串开头时,才会根据systemId进一步查找相应的dtd,并返回inputSource实现,否则即返回默认的null。以前一个实现,hibernate会寻找到包org/hibernate包下的一个hibernate-configuration-3.0.dtd,此文件被封装到hibernate-core.jar中。这样就可以正常地进行解析和验证了。

实际上很多的sax解析器都是使用此种解析方式来进行解析,包括struts2等,这种解析方式,即保证了xml格式能够被验证,同时又保证了不需要通过网络下载相应的dtd声明,在程序内部就可以实现dtd获取和下载了。

关于如何使用entityResolver,还有一个网址可以参考下:http://www.ibm.com/developerworks/cn/xml/tips/x-tipent/index.html

转载请标明出处:i flym

本文地址:http://www.iflym.com/index.php/code/usr-right-dtd-declaration-and-entityresolver-to-avoid-saxreader-validate-by-network.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: