Spring的XML解析中关于DTD的路径问题-

在Spring中最简单的一个xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC  "-//SPRING//DTD BEAN//EN"  " http://www.springframework.org/dtd/spring-beans.dtd ">
<beans>
        <bean id="hello" class="com.test.Hello" singleton="true"/>
</beans>
但是这里的DTD使用的是网络路径,如果电脑没有上网的话,那么Spring读取这个XML就一定会出问题,因为无法到达这个网络地址,解决方法就是使用本地的DTD,那么路径应该如何设置呢?一般我们的配置文件都是放在classes目录下的,也就是在Classpath下,那么是不是要把spring-beans.dtd放到classes里面呢?不行,来看一下Spring中org.springframework.beans.factory.xml.BeansDtdResolver这个类的源代码:
/*
 * Copyright 2002-2004 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springframework.beans.factory.xml;
import java.io.IOException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
/**
 * EntityResolver implementation for the Spring beans DTD,
 * to load the DTD from the Spring classpath resp. JAR file.
 *
 * <p>Fetches "spring-beans.dtd" from the classpath resource
 * "/org/springframework/beans/factory/xml/spring-beans.dtd",
 * no matter if specified as some local URL or as
 * " http://www.springframework.org/dtd/spring-beans.dtd ".
 *
 * @author Juergen Hoeller
 * @since 04.06.2003
 */
public class BeansDtdResolver implements EntityResolver {
 private static final String DTD_NAME = "spring-beans";
 private static final String SEARCH_PACKAGE = "/org/springframework/beans/factory/xml/";
 protected final Log logger = LogFactory.getLog(getClass());
 public InputSource resolveEntity(String publicId, String systemId) throws IOException {
  logger.debug("Trying to resolve XML entity with public ID [" + publicId +
         "] and system ID [" + systemId + "]");
  if (systemId != null && systemId.indexOf(DTD_NAME) > systemId.lastIndexOf("/")) {
   String dtdFile = systemId.substring(systemId.indexOf(DTD_NAME));
   logger.debug("Trying to locate [" + dtdFile + "] under [" + SEARCH_PACKAGE + "]");
   try {
    Resource resource = new ClassPathResource(SEARCH_PACKAGE + dtdFile, getClass());
    InputSource source = new InputSource(resource.getInputStream());
    source.setPublicId(publicId);
    source.setSystemId(systemId);
    logger.debug("Found beans DTD [" + systemId + "] in classpath");
    return source;
   }
   catch (IOException ex) {
    logger.debug("Could not resolve beans DTD [" + systemId + "]: not found in classpath", ex);
   }
  }
  // use the default behaviour -> download from website or wherever
  return null;
 }
}
很清楚Spring已经把/org/springframework/beans/factory/xml/这个路径写死到代码里了,所以我们也只能把spring-beans.dtd放到这个目录下,才可以保证被xml解析引擎解析到,当然这里也可以使用绝对路径,但是这样的话,就很难在移植了,所以还是使用相对路径比较好,而且Spring已经把这个spring-beans.dtd打包到spring.jar文件中了。
 
好,现在已经确定是使用相对路径了,那么相对路径应该怎么写呢?看之前要搞清楚Spring用的是什么解析引擎,由于Spring使用的是JAXP解析XML文件的,在不做特殊声明的情况下,JDK会使用Crimson解析引擎,具体见Robbin的分析: http://forum.javaeye.com/viewtopic.php?t=75
好了,现在就来看一下Crimson这个解析引擎,在解析DTD时候的代码:
private String resolveURI(String uri)
        throws SAXException
    {
        int     temp = uri.indexOf (':');
        // resolve relative URIs ... must do it here since
        // it's relative to the source file holding the URI!
        // "new java.net.URL (URL, string)" conforms to RFC 1630,
        // but we can't use that except when the URI is a URL.
        // The entity resolver is allowed to handle URIs that are
        // not URLs, so we pass URIs through with scheme intact
        if (temp == -1 || uri.indexOf ('/') < temp) {
            String      baseURI;
            baseURI = in.getSystemId ();
            if (baseURI == null)
                fatal ("P-055", new Object [] { uri });
            if (uri.length () == 0)
                uri = ".";
            baseURI = baseURI.substring (0, baseURI.lastIndexOf ('/') + 1);
            if (uri.charAt (0) != '/')
                uri = baseURI + uri;
            else {
                // We have relative URI that begins with a '/'
                // Extract scheme including colon from baseURI
                String baseURIScheme;
                int colonIndex = baseURI.indexOf(':');
                if (colonIndex == -1) {
                    // Base URI does not have a scheme so default to
                    // "file:" scheme
                    baseURIScheme = "file:";
                } else {
                    baseURIScheme = baseURI.substring(0, colonIndex + 1);
                }
                uri = baseURIScheme + uri;
            }
            // letting other code map any "/xxx/../" or "/./" to "/",
            // since all URIs must handle it the same.
        }
        // check for fragment ID in URI
        if (uri.indexOf ('#') != -1)
            error ("P-056", new Object [] { uri });
        return uri;
    }
由此可知路径里面必须包含":" 和"/"而且":"还必须在"/"的前面,所以这个路径我们可以最简单的写成 ":/spring-beans.dtd" 就可以了。当然":"前面在加上其他的什么路径都不影响解析。
Spring的XML解析中关于DTD的路径问题-  

你可能感兴趣的:(spring,xml,String,Scheme,import,permissions)