Подтвердить что ты не робот

Сделать 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;
}
4b9b3361

Ответ 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>