`

解决java web容器解析xml不能找到DTD问题

    博客分类:
  • XML
阅读更多

项目创建了一个dtd文件,放在tomcat webapp class 目录下面,xml也位于class目录下,xml 的 dtd引用直接为dtd文件名。但是解析时并不是根据xml的相对路径取找dtd文件,而是在执行目录下(也就是tomcat bin目录)下查找,当然找不到。(给xml的dtd引用加上斜杠表示相对路径也没用)
  在网上找了很久,终于有了一个解决方案,与大家共享:

       用DOM解析的时候,我们可以自定义实体的解析器(EntityResolver),而不是使用默认的实体解析器。(默认的解析器会根据实际的url进行读取)
from:http://www.javayou.com/diary/623


般比较正式的XML信息中都会包含对应的DTD声明,用来定义该XML文档中的格式,例如WEB项目中用到的web.xml,例如struts的配置文件struts-config.xml,下面是web.xml中用到的DTD信息:

 

<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
       "
http://java.sun.com/dtd/web-app_2_3.dtd">

当我们用DOM或者Digester来解析这个XML的时候,如果当前计算机已联网那么解析的速度比较慢,如果当前计算机未联网则会报无法连接主机的异常。这是因为XML的解析器需要读取dtd的内容,而这个dtd文件是存在于互联网的某台主机上的,因此问题就在于:如果我们的计算机不能保证时时都连在网上,那么怎么老保证解析过程不出错呢?下面我们分别就两种不同的解析方法进行说明。

1. 使用DOM解析

使用DOM解析的时候,我们可以自定义实体的解析器(EntityResolver),而不是使用默认的实体解析器,因为默认的解析器会根据实际的url进行读取,下面是一段如何来解析web.xml的代码:

 

private static void parse(InputStream in) throws Exception{
  DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
  DocumentBuilder db = dbf.newDocumentBuilder();
  
db.setEntityResolver(new EntityResolver(){
   public InputSource resolveEntity(String publicId, String systemId)
    throws SAXException, IOException{
          for (int i = 0; i < registrations.length; i += 2) {
           if(publicId.equals(registrations[i])){
            String dtd_uri = registrations[i+1];
               InputStream dtd_stream = this.getClass().getResourceAsStream(dtd_uri);
      return new InputSource(dtd_stream);
           }
          }
    return null;
   }});

  Document doc = db.parse(in);
  Element root = doc.getDocumentElement();
  NodeList nodes = root.getElementsByTagName("servlet-mapping");
  int nodec = nodes.getLength();
  for(int i=0;i<nodec;i++){
   Element node = (Element)nodes.item(i);
   Element servlet_name = (Element)node.getElementsByTagName("servlet-name").item(0);
   Element url_pattern = (Element)node.getElementsByTagName("url-pattern").item(0);
   
   String sn = servlet_name.getFirstChild().getNodeValue();
   String up = url_pattern.getFirstChild().getNodeValue();
   System.out.println(sn+"="+up);
  }
 }

private final static String registrations[] = {
        "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN",
        "/web-app_2_2.dtd",
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN",
        "/web-app_2_3.dtd"
};

这段代码中把本来从http://java.sun.com/dtd/web-app_2_3.dtd地址中读取dtd的信息改为了从当前类路径中读取,也就是/web-app_2_3.dtd,通过重新定义InputSource来返回/web- app_2_3.dtd数据流,从而让XML解析器不从网上获取DTD信息。当然,这样做的前提是事先必须把dtd文件保存在类路径所在的目录中,以便自定义的EntityResolver可以读取到。

2. 使用Digester解析

使用Digester解析时原理也是一样的,代码有所不同而已:

 

Digester digester = new Digester();
digester.push(this);
digester.setNamespaceAware(true);
digester.setValidating(false);

// Register our local copy of the DTDs that we can find
for (int i = 0; i < registrations.length; i += 2) {
    URL url = this.getClass().getResource(registrations[i+1]);
    if (url != null)
        digester.register(registrations[i], url.toString());            
}

其中registrations与前一段代码相同。

通过上面两种处理办法以后,XML的解析器就不再从网上获取dtd文件,这也是为什么Tomcat包括struts项目可以在计算机没有联网下工作的原因,因为Tomcat需要解析web.xml,struts需要解析web.xml以及struts-config.xml,而这两个文件的dtd恰恰都是通过一个url给出的。

需要说明一点的是,这样做的目的并不是说屏蔽了DTD的作用,毕竟DTD是用来验证XML语法的,如果去掉了,验证的功能就没有了,因此DTD不能去掉。这样做的真正目的是在保留DTD功能外使应用程序在无网络连接的情况下也可以运行。

分享到:
评论

相关推荐

    JAVA WEB 开发详解:XML+XSLT+SERVLET+JSP 深入剖析与实例应用.part2

    此外,本书的配套光盘还免费提供了价值人民币330元的java教学视频,对java语言进行了全面讲解,帮助一些不会java语言的读者快速地从java基础知识的学习中过渡到java web的学习与开发上. 第1部分 xml篇. 第1章 xml...

    JAVA WEB 开发详解:XML+XSLT+SERVLET+JSP 深入剖析与实例应用.part3

    此外,本书的配套光盘还免费提供了价值人民币330元的java教学视频,对java语言进行了全面讲解,帮助一些不会java语言的读者快速地从java基础知识的学习中过渡到java web的学习与开发上. 第1部分 xml篇. 第1章 xml...

    JAVA WEB 开发详解:XML+XSLT+SERVLET+JSP 深入剖析与实例应用.part4

    此外,本书的配套光盘还免费提供了价值人民币330元的java教学视频,对java语言进行了全面讲解,帮助一些不会java语言的读者快速地从java基础知识的学习中过渡到java web的学习与开发上. 第1部分 xml篇. 第1章 xml...

    JAVA WEB 开发详解:XML+XSLT+SERVLET+JSP 深入剖析与实例应用.part5

    此外,本书的配套光盘还免费提供了价值人民币330元的java教学视频,对java语言进行了全面讲解,帮助一些不会java语言的读者快速地从java基础知识的学习中过渡到java web的学习与开发上. 第1部分 xml篇. 第1章 xml...

    java 面试题 总结

     GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收...

    Java语言基础下载

    第二十二章:使用Java解析XML 397 学习目标 397 解析器的介绍 398 DOM以及广义的基于树的处理具有几个优点 399 文档对象模型(DOM)解析实例 402 DOM对象 404 DOM解析的例子: 406 SAX解析实例 409 DOM4J解析实例 ...

    超级有影响力霸气的Java面试题大全文档

     GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收...

    Spring 2.0 开发参考手册

    9.9. 公共问题的解决方案 9.9.1. 对一个特定的 DataSource 使用错误的事务管理器 9.10. 更多的资源 10. DAO支持 10.1. 简介 10.2. 一致的异常层次 10.3. 一致的DAO支持抽象类 11. 使用JDBC进行数据访问 11.1....

    Spring中文帮助文档

    9.9. 常见问题的解决方法 9.9.1. 对一个特定的 DataSource 使用了错误的事务管理器 9.10. 更多的资源 10. DAO支持 10.1. 简介 10.2. 一致的异常层次 10.3. 一致的DAO支持抽象类 11. 使用JDBC进行数据访问 ...

    Spring API

    9.9. 常见问题的解决方法 9.9.1. 对一个特定的 DataSource 使用了错误的事务管理器 9.10. 更多的资源 10. DAO支持 10.1. 简介 10.2. 一致的异常层次 10.3. 一致的DAO支持抽象类 11. 使用JDBC进行数据访问 ...

    spring chm文档

    9.9. 公共问题的解决方案 9.9.1. 对一个特定的 DataSource 使用错误的事务管理器 9.10. 更多的资源 10. DAO支持 10.1. 简介 10.2. 一致的异常层次 10.3. 一致的DAO支持抽象类 11. 使用JDBC进行数据访问 11.1....

    Spring-Reference_zh_CN(Spring中文参考手册)

    9.9. 公共问题的解决方案 9.9.1. 对一个特定的 DataSource 使用错误的事务管理器 9.10. 更多的资源 10. DAO支持 10.1. 简介 10.2. 一致的异常层次 10.3. 一致的DAO支持抽象类 11. 使用JDBC进行数据访问 11.1. 简介 ...

Global site tag (gtag.js) - Google Analytics