EntityResolver

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

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


这就是说,对于解析一个xml,sax首先读取该xml文档上的声明,根据声明去寻找相应的dtd定义,以便对文档进行一个验证。默认的寻找规则,即通过网络(实现上就是声明的dtd的uri地址)来下载相应的dtd声明,并进行认证。下载的过程是一个漫长的过程,而且当网络中断或不可用时,这里就会报错的,就是因为相应的dtd声明没有被找到的原因。
    entityResolver的作用就是项目本身就可以提供一个如何寻找dtd声明的方法,即由程序来实现寻找dtd声明的过程,比如我们将dtd文件放到项目中某处,在实现时直接将此文档读取并返回给sax,即可。这样就避免了通过网络来寻找相应的声明。


这里,它接收两个参数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,继续参看其实现:



public InputSource resolveEntity(String publicId, String systemId) {
        if ( systemId != null ) {
            if ( systemId.startsWith( HIBERNATE_NAMESPACE ) ) {
                String path = "org/hibernate/" + systemId.substring( HIBERNATE_NAMESPACE.length() );
                InputStream dtdStream = resolveInHibernateNamespace( path );
                    InputSource source = new InputSource( dtdStream );
                    source.setPublicId( publicId );
                    source.setSystemId( systemId );
                    return source;
            }
            else if ( systemId.startsWith( USER_NAMESPACE ) ) {
                String path = systemId.substring( USER_NAMESPACE.length() );
                InputStream stream = resolveInLocalNamespace( path );
             
                    InputSource source = new InputSource( stream );
                    source.setPublicId( publicId );
                    source.setSystemId( systemId );
                    return source;
            }
        }
        // use default behavior
        return null;
    }



看其实现,即是首先判断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


你可能感兴趣的:(EntityResolver)