Зробіть DocumentBuilder.parse ігнорувати посилання на DTD


82

Коли я аналізую свій файл 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
Я вважаю, що jt має найкращу відповідь на це питання.
simgineer

Відповіді:


59

Подібний підхід, запропонований @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 працювало так само добре?


4
Налаштування функцій DocumentBuilderFactory працювало у мене. Рішення в цій публікації не спрацювало.
Kai Mechel

4
Це також прекрасно спрацювало для мене, хоча я думав, що не використовую SAX
devnull69

На жаль, це не спрацювало для мене. Я все-таки отримав помилку. @jt це зробив для мене.
Nils-o-mat

Дякую за рішення, я вважаю , такий підхід рекомендує org.xml . Схоже, матеріалу на цю тему дуже багато. см xerces.apache.org/xml-commons/components/resolver / ... або en.wikipedia.org/wiki/XML_Catalog і JavaDoc saxproject.org/apidoc/org/xml/sax/EntityResolver.html і saxproject.org/ apidoc / org / xml / sax / ext / EntityResolver2.html
aliopi

135

Спробуйте встановити функції у 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, якщо це допоможе.


21
останній ( load-external-dtd) зробив для мене фокус - спасибі.
Amarghosh

1
Спробувавши це, я отримав DOMException: NAMESPACE_ERR: робиться спроба створити або змінити об’єкт способом, який є неправильним щодо просторів імен. . Я виправив це за допомогоюdbf.setNamespaceAware(true);
Tim Van Laer

Тільки щоб повідомити, останнє налаштування функції (як заявив @Amarghosh) чудово працює з SAXParserFactory.
Alexis Leclerc

1
Для мене load-external-dtdналаштування було достатньо.
Кріс

Використання всіх вищезазначених функцій також призводить до збою коду. Просто використання двох останніх функцій (неперевіряючих) змушує мій код працювати.
Пурус,

5

Я виявив проблему, коли файл 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

Джерело 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 як рядка та видалення декларації 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> 

2

Я знаю, що у мене немає dtd, і він мені не потрібен.

Я підозрілий до цього твердження; чи містить ваш документ посилання на сутність? Якщо так, то вам обов’язково потрібен DTD.

У будь-якому випадку, звичайним способом запобігти цьому є використання XML-каталогу для визначення локального шляху для "map.dtd".


2

ось ще один користувач, який отримав ту ж проблему: 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, зупиняючи всі перевірки ..."

Сподіваюся, це допомагає.


0

Я працюю з sonarqube, і sonarlint для eclipse показав мені, що ненадійний XML повинен бути проаналізований без вирішення зовнішніх даних (squid: S2755)

Мені вдалося вирішити це за допомогою:

    factory = DocumentBuilderFactory.newInstance();

    factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);

    // If you can't completely disable DTDs, then at least do the following:
    // Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-general-entities
    // Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-general-entities
    // JDK7+ - http://xml.org/sax/features/external-general-entities
    factory.setFeature("http://xml.org/sax/features/external-general-entities", false);

    // Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-parameter-entities
    // Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-parameter-entities
    // JDK7+ - http://xml.org/sax/features/external-parameter-entities
    factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);

    // Disable external DTDs as well
    factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);

    // and these as well, per Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks"
    factory.setXIncludeAware(false);
    factory.setExpandEntityReferences(false);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.