我们用 JDOM 解析 XML 最简单的代码莫过于以下两行代码,不过为了测试我们在其前后加上记录执行时间的代码:
long start = System.currentTimeMillis();
SAXBuilder builder = new SAXBuilder();
Document document = builder.build("struts-config.xml");
System.out.println("耗时:" + (System.currentTimeMillis()-start)+" 毫秒.");
long start = System.currentTimeMillis();
SAXBuilder builder = new SAXBuilder();
Document document = builder.build("struts-config.xml");
System.out.println("耗时:" + (System.currentTimeMillis()-start)+" 毫秒.");
在这个 struts-config.xml 中的 DTD 声明如下:
<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_3.dtd">
<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_3.dtd">
正常执行时,打印出的耗时是 2698 毫秒(五次的平均值),这是能正常访问 http://jakarta.apache.org/struts/dtds/struts-config_1_3.dtd 的情况下。假如把网线拔了,再执行上面的代码,就会报出下面的异常:
Exception in thread "main" java.net.UnknownHostException: jakarta.apache.org
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:177)
.......................................................
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:977)
at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:677)
at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.startEntity(XMLEntityManager.java:1315)
at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.startDTDEntity(XMLEntityManager.java:1282)
at com.sun.org.apache.xerces.internal.impl.XMLDTDScannerImpl.setInputSource(XMLDTDScannerImpl.java:283)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$DTDDriver.dispatch(XMLDocumentScannerImpl.java:1176)
........................................................
很明显,前面的代码要从网络上读取 struts-config_1_3.dtd 来进行验证,于是有了第一个加速的办法:本地 DTD 验证。从本地读取 struts-config_1_3.dtd 文件,从 http://jakarta.apache.org/struts/dtds/struts-config_1_3.dtd 下载 struts-config_1_3.dtd 放到 struts-config.xml 同一目录。然后修改 struts-config.xml 的 DTD 声明如下:
<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN"
"struts-config_1_3.dtd">
<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN"
"struts-config_1_3.dtd">
再执行上面的代码,打印出的耗时是 717 毫秒(五次的平均值),比前面的 2698 节省了 73.4 的时间,我所用的网络带宽也是能 BT 到 250 K的那种。
前面两种情况都是进行了 DTD 验证的情形,如果我们能给予 XML 充分信任时,就可以不进行 DTD 验证,这是一种极端,这时候管不管你有没有接网线都不在乎了。因此这第二种办法就是 不进行 DTD 验证。
查了一下 SAXBuilder 的 API http://www.jdom.org/docs/apidocs/org/jdom/input/SAXBuilder.html,有构造方法 SAXBuilder(boolean validate) 和一个实例方法 setValidation(boolean validate) 。望文生义,似乎把参数设置为 false,就能合乎不进行 DTD 验证的要求,可是错了,validate 的默认值就是 false。SAXBuilder 还有一个方法 setDTDHandler(org.xml.sax.DTDHandler dtdHandler) 好像也是干这事的,于是试了一下让 DTDHandler 无所作为:
builder.setDTDHandler(new DTDHandler(){
public void notationDecl(String name, String publicId,
String systemId) throws SAXException {
}
public void unparsedEntityDecl(String name, String publicId,
String systemId, String notationName) throws SAXException {
}
});
builder.setDTDHandler(new DTDHandler(){
public void notationDecl(String name, String publicId,
String systemId) throws SAXException {
}
public void unparsedEntityDecl(String name, String publicId,
String systemId, String notationName) throws SAXException {
}
});