本文转载自:
http://blog.csdn.net/chjttony/article/details/7720873说在前面
读取XML的时候,很多人总是不明白为什么会连接超时,XML解析怎么还会访问网络,其实在XML解析之前,如果XML指定了DTD文件,那么Java会根据DTD文件的路径去本地寻找或远程下载,下载的时候就会出现连接超时!所以想要避免连接超时这个问题,就可以采用避免DTD下载,下面通过两种方式避免DTD下载,本人亲测,确实是一篇好文章,谢谢作者!
下面是正文:
Java程序在解析xml文件时,如果xml文件中指定了dtd,在默认会从指定的url下载dtd文件,但是很多情况下如果网络连接不上,或者防火墙原因,dtd文件无法下载下来导致程序报连接超时异常,解析xml失败。有两种方法解决该类问题:
1.指定从本地读取dtd文件
若要解析的xml文件中有如下的dtd声明:
<!DOCTYPE concept PUBLIC "-//OASIS//DTD DITA Concept//EN" "
http://docs.oasisopen.org/dita/v1.2/os/dtd1.2/technicalContent/dtd/concept.dtd
">
publicId:被引用的外部实体的公共标识符,如果未提供,则为 null。
上述的dtd声明中publicId为-//OASIS//DTD DITA Concept//EN
systemId:被引用的外部实体的系统标识符。
上述的dtd声明中systemId为http://docs.oasis-open.org/dita/v1.2/os/dtd1.2/technicalContent/dtd/concept.dtd
可以通过重新SAX的EntityResolver类的resolveEntity(String publicId, String systemId) throws SAXException, IOException方法指定读取本地的dtd文件,该放在在XML解析器解析xml之前调用,用于加载指定的dtd文件:
/**
* Implementation of <code>org.xml.sax.EntityResolver</code> that loads
* entitities (for example dtd files) from the classpath.
*/
public class ClasspathEntityResolver
implements EntityResolver
{
public InputSource resolveEntity(String publicId, String systemId)
throws SAXException, IOException
{
if (systemId != null)
{
int index = systemId.lastIndexOf('/');
if (index != -1)
{
systemId = systemId.substring(index + 1);
}
systemId = "/" + systemId;
InputStream istr = Thread.currentThread().getContextClassLoader().getResourceAsStream(systemId);
if (istr != null)
{
return new InputSource(istr);
}
}
return null;
}
}
在SAX解析xml文件之前,指定使用自定义的ClasspathEntityResolver:
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser saxParser = spf.newSAXParser();
xmlReader = saxParser.getXMLReader();
xmlReader.setEntityResolver(new ClasspathEntityResolver());
xmlReader.setContentHandler(handler);
try {
xmlReader.parse(new InputSource(inputFilePath));
} catch (Exception e) {
e.printStackTrace();
}
注意:
经测试发现,这种方法只对SYSTEM(本地dtd)有效,如:
<!DOCTYPE concept PUBLIC "-//OASIS//DTD DITA Concept//EN" "
http://docs.oasisopen.org/dita/v1.2/os/dtd1.2/technicalContent/dtd/concept.dtd
">
PUBLIC方式的dtd依然从外部下载dtd,只能通过第二种方式忽略dtd校验。
2.解析xml文件时彻底忽略dtd:
SAX解析器可以通过指定http://apache.org/xml/features/nonvalidating/load-external-dtd属性来确定是否忽略dtd,例子如下:
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser saxParser = spf.newSAXParser();
xmlReader = saxParser.getXMLReader();
xmlReader.setFeature("
http://apache.org/xml/features/nonvalidating/load-external-dtd
", false);
xmlReader.setContentHandler(handler);
try {
xmlReader.parse(new InputSource(inputFilePath));
} catch (Exception e) {
e.printStackTrace();
}