在最近的一个项目中,我用到Dom4j去解析现有的Spring2.0中的bean节点,从中获取一些公用的属性信息。
// Get params of hsql setting from web context SAXReader xmlReader = new SAXReader(); Document doc = xmlReader.read(getSpringContextFilePath(sce)); Element beanNode = (Element) doc.selectSingleNode("/beans/bean[@id='DatabaseParam']");
这段代码在电脑连接到互联网上的时候工作都正常,但是如果电脑在端线状态的时候就会报错如下:
org.dom4j.DocumentException: www.springframework.org Nested exception: www.springframework.org
at org.dom4j.io.SAXReader.read(SAXReader.java:484)
at org.dom4j.io.SAXReader.read(SAXReader.java:321) ....
看错误的提示,应该是说现在电脑无法找到一个www.springframework.org 的网络主机。
仔细察看一下Spring的配置文件头,里面有如下的一个头文件注释:
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
问题就出现在这里!xmlReader.read 读取Spring配置文件的时候报错。
所以,我们需要替换掉这里的http://www.springframework.org/ 为一个本地的dtd文件。如何替换呢?
可以考虑将这里的http:///协议的路径改为一个file:/// 方式的本地文件,但是这样路径就指定死了,不便于程序移植。
另外一种方案就是,为这里的xmlReader添加一个EntiyResolver:
// Set a resolver for reader to locate dtd file for Spring xmlReader.setEntityResolver(new EntityResolver() { public InputSource resolveEntity(String publicId, String systemId) { if (publicId.equals("-//SPRING//DTD BEAN//EN")) { InputStream in = getClass().getResourceAsStream( "/spring-beans-2.0.dtd"); return new InputSource(in); } return null; } });
这样,每一次的xmlReader调用时,dom4j首先就会去从本地的classpath下面去寻找一个相应的dtd去处理,问题也就迎刃而解了。
可能有人有另外的疑问了,为什么Spring本身解析xml没有出现过这个错误呢? 其实Spring会首先在本地的固定路径中寻找spring-beans-2.0.dtd文件(具体在spring-beans.jar包中的com.springframework.beans.factory.xml路径下),如果找不到,然后才会参照DOCTYPE中的地址去寻找。