소스참조: http://www.ibm.com/developerworks/library/x-tipent.html
원인)
xml validation을 하다보면 (builder.parse~~부분)
xml파일이 있는 경로에 dtd이 없거나, 현재 시스템이 사용중인 디렉토리에서 계속 dtd를 읽어들어
dtd파일을 찾을 수 없어 validation을 처리할 수 없는 경우를 종종 경험했다.
예) xml 문서에
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Message PUBLIC "-//LEE//JIN" "TEST.dtd">
...............
와 같이 되어있다면 /../../../TEST.dtd 지정된 경로에 파일을 찾을 수 없습니다.
해결방법)
EntityResolver을 사용하는 것이다.
EntityResolver를 사용하면 외부의 dtd를 두고 xml을 파싱하여 validation을 체크할 수 있다.
EntityResolver는
The Parser will call this method before opening any external entity except the top-level document entity (including the external DTD subset, external entities referenced within the DTD, and external entities referenced within the document element): the application may request that the parser resolve the entity itself, that it use an alternative URI, or that it use an entirely different input source.
소스)
class DTDResolver implements EntityResolver {
public InputSource resolveEntity(String publicID, String systemID)
throws SAXException {
System.out.println(systemID.toString());
if (systemID.equals("TEST.dtd")) {
// Return local copy of the copyright.xml file
return new InputSource("/lee/jin/test/TEST.dtd");
}
// If no match, returning null makes process continue normally
return null;
}
}
여기서 pulbicId와 Systemid를 받는데 xml의 doctype을 보면
<!DOCTYPE Message PUBLIC "-//LEE//JIN" "TEST.dtd">
"-//LEE//JIN" 가 publicID, "TEST.dtd"가 SystemID 이다.
그렇기에 xml문서에서 "TEST.dtd"를 만나게 되면 "/lee/jin/test/TEST.dtd"를 리턴하라는 것이다.
즉 어디에 있는 xml을 불러들이건 특정 한 경로에 dtd파일이 있으면 그것을 참조하여 xml을 파싱하기때문에 여러곳에 dtd를 넣고 작업하지 않아도 된다.
(만약 위와같이 했는데도 TEST.dtd를 찾지 못한다면 SystemID.endsWith를 사용하여 처리하면 해결 할 수 있다.)
API참고:
http://download.oracle.com/javase/1.4.2/docs/api/org/xml/sax/EntityResolver.html