2007/03/02
DocumentBuilder がリモート DTD を読みにいかないようにする
少し意外なのですが、 DocumentBuilder.parse はリモート DTD の場合でも強引に読みにいくらしいことが判明しました。ドキュメントをバリデートするためではなく( setValidation(false) )、パース中に遭遇したエンティティを解決するためにあらかじめ DTD を読みにいくのですが、インターネット環境が万全であることを前提としていないアプリケーションでは少しばかり困ったことになります(エンティティに遭遇するまで読みにいくのを遅延するぐらいはしてくれてもいいと思うのです)。 そういう時は以下のようなコードを加えてローカルから DTD を引っぱるようにしましょう。
HogeResolver.java:
package hoge; import java.io.IOException; import java.io.FileInputStream; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; public class HogeResolver implements EntityResolver { private static final String DTD_NAME = "hogehoge"; public InputSource resolveEntity(String publicId, String systemId) throws IOException { try { if (systemId != null && systemId.indexOf(DTD_NAME) > systemId.lastIndexOf("/")) { InputSource source = new InputSource(new FileInputStream("hogehoge.dtd")); source.setPublicId(publicId); source.setSystemId(systemId); return source; } } catch (IOException ex) { } return null; } }
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); builder.setEntityResolver(new HogeResolver()); Document doc = builder.parse(new File(fileName)); // ...
例えば以下のように DOCTYPE を宣言すればリモートからではなくローカルから DTD をひっぱってくるようになります。
<!DOCTYPE beans PUBLIC "-//HOGE//DTD HOGE//EN" "http://hoge/hogehoge.dtd">
ちなみに resolveEntity で null を返した場合はエラーではなくてデフォルトの振舞いになるので気をつけましょう。
- Category(s)
- java
- The URL to Trackback this entry is:
- http://dev.ariel-networks.com/Members/matsuyama/let-documentbuilder-not-to-read-remote-DTD/tbping