Сделать DocumentBuilder.parse игнорировать ссылки DTD
Когда я разбираю свой XML файл (переменная f) в этом методе, я получаю сообщение об ошибке
C:\Documents and Settings\joe\Desktop\aicpcudev\OnlineModule\map.dtd(система не может найти указанный путь)
Я знаю, что у меня нет dtd, и мне это не нужно. Как я могу проанализировать этот объект File в объекте Document при игнорировании опорных ошибок DTD?
private static Document getDoc(File f, String docId) throws Exception{
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(f);
return doc;
}
Ответы
Ответ 1
Аналогичный подход к предложению @anjanb
builder.setEntityResolver(new EntityResolver() {
@Override
public InputSource resolveEntity(String publicId, String systemId)
throws SAXException, IOException {
if (systemId.contains("foo.dtd")) {
return new InputSource(new StringReader(""));
} else {
return null;
}
}
});
Я обнаружил, что простое возвращение пустого InputSource работало так же хорошо?
Ответ 2
Попробуйте установить параметры на DocumentBuilderFactory:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setValidating(false);
dbf.setNamespaceAware(true);
dbf.setFeature("http://xml.org/sax/features/namespaces", false);
dbf.setFeature("http://xml.org/sax/features/validation", false);
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
DocumentBuilder db = dbf.newDocumentBuilder();
...
В конечном счете, я думаю, что варианты специфичны для реализации парсера. Вот некоторая документация для Xerces2, если это помогает.
Ответ 3
Я нашел проблему, когда файл DTD находился в файле jar вместе с XML. Я решил проблему, основанную на примерах здесь, следующим образом: -
DocumentBuilder db = dbf.newDocumentBuilder();
db.setEntityResolver(new EntityResolver()
{
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException
{
if (systemId.contains("doc.dtd"))
{
InputStream dtdStream = MyClass.class
.getResourceAsStream("/my/package/doc.dtd");
return new InputSource(dtdStream);
}
else
{
return null;
}
}
});
Ответ 4
Я знаю, что у меня нет dtd, и мне это не нужно.
Я с подозрением отношусь к этому утверждению; содержит ли ваш документ какие-либо ссылки на сущности? Если это так, вам определенно нужен DTD.
В любом случае обычным способом предотвращения этого является использование каталога XML для определения локального пути для "map.dtd".
Ответ 5
здесь другой пользователь, который получил ту же проблему: http://forums.sun.com/thread.jspa?threadID=284209&forumID=34
Пользователь ddssot на этом сообщении говорит
myDocumentBuilder.setEntityResolver(new EntityResolver() {
public InputSource resolveEntity(java.lang.String publicId, java.lang.String systemId)
throws SAXException, java.io.IOException
{
if (publicId.equals("--myDTDpublicID--"))
// this deactivates the open office DTD
return new InputSource(new ByteArrayInputStream("<?xml version='1.0' encoding='UTF-8'?>".getBytes()));
else return null;
}
});
Пользователь далее упоминает: "Как вы можете видеть, когда парсер попадает в DTD, вызывается распознаватель сущности. Я узнаю свой DTD с его конкретным идентификатором и возвращу пустой XML-документ вместо реального DTD, останавливая всю проверку..."
Надеюсь, что это поможет.
Ответ 6
Исходный XML (с DTD)
<!DOCTYPE MYSERVICE SYSTEM "./MYSERVICE.DTD">
<MYACCSERVICE>
<REQ_PAYLOAD>
<ACCOUNT>1234567890</ACCOUNT>
<BRANCH>001</BRANCH>
<CURRENCY>USD</CURRENCY>
<TRANS_REFERENCE>201611100000777</TRANS_REFERENCE>
</REQ_PAYLOAD>
</MYACCSERVICE>
Реализация Java DOM для принятия выше XML как String и удаления объявления DTD
public Document removeDTDFromXML(String payload) throws Exception {
System.out.println("### Payload received in XMlDTDRemover: " + payload);
Document doc = null;
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
dbf.setValidating(false);
dbf.setNamespaceAware(true);
dbf.setFeature("http://xml.org/sax/features/namespaces", false);
dbf.setFeature("http://xml.org/sax/features/validation", false);
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
DocumentBuilder db = dbf.newDocumentBuilder();
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(payload));
doc = db.parse(is);
} catch (ParserConfigurationException e) {
System.out.println("Parse Error: " + e.getMessage());
return null;
} catch (SAXException e) {
System.out.println("SAX Error: " + e.getMessage());
return null;
} catch (IOException e) {
System.out.println("IO Error: " + e.getMessage());
return null;
}
return doc;
}
Целевой XML (без DTD)
<MYACCSERVICE>
<REQ_PAYLOAD>
<ACCOUNT>1234567890</ACCOUNT>
<BRANCH>001</BRANCH>
<CURRENCY>USD</CURRENCY>
<TRANS_REFERENCE>201611100000777</TRANS_REFERENCE>
</REQ_PAYLOAD>
</MYACCSERVICE>