Ustaw DocumentBuilder.parse ignorować odniesienia DTD

82

Kiedy analizuję mój plik xml (zmienna f) w tej metodzie, pojawia się błąd

C: \ Documents and Settings \ joe \ Desktop \ aicpcudev \ OnlineModule \ map.dtd (system nie może znaleźć określonej ścieżki)

Wiem, że nie mam dtd i nie potrzebuję go. Jak mogę przeanalizować ten obiekt File w obiekt Document, ignorując błędy odniesienia 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;
}
joe
źródło
1
Uważam, że jt ma najlepszą odpowiedź na to pytanie.
simgineer

Odpowiedzi:

59

Podejście podobne do sugerowanego przez @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;
            }
        }
    });

Okazało się, że po prostu zwrócenie pustego źródła danych wejściowych działa równie dobrze?

zestaw narzędzi
źródło
4
Ustawienie funkcji w DocumentBuilderFactory działało dla mnie. Rozwiązanie w tym poście nie działało.
Kai Mechel
4
To również działało idealnie dla mnie, chociaż myślałem, że nie używam SAX
devnull69
Niestety to nie zadziałało dla mnie. Nadal mam błąd. @jt zrobił to jednak dla mnie.
Nils-o-mat
Dzięki za rozwiązanie, myślę , że jest to podejście zalecane przez org.xml . Wygląda na to, że jest dużo materiału na ten temat. patrz xerces.apache.org/xml-commons/components/resolver/… lub en.wikipedia.org/wiki/XML_Catalog i javadoc saxproject.org/apidoc/org/xml/sax/EntityResolver.html i saxproject.org/ apidoc / org / xml / sax / ext / EntityResolver2.html
aliopi
135

Spróbuj ustawić funkcje w 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();
...

Ostatecznie myślę, że opcje są specyficzne dla implementacji parsera. Tutaj jest trochę dokumentacji dla Xerces2, jeśli to pomoże.

jt.
źródło
21
ostatni ( load-external-dtd) załatwił mi sprawę - dzięki.
Amarghosh
1
Próbując tego, otrzymałem DOMException: NAMESPACE_ERR: Podjęto próbę utworzenia lub zmiany obiektu w sposób, który jest nieprawidłowy w odniesieniu do przestrzeni nazw. . Naprawiłem to zdbf.setNamespaceAware(true);
Tim Van Laer,
Abyś wiedział, ostatnie ustawienie funkcji (jak stwierdzono przez @Amarghosh) działa świetnie z SAXParserFactory.
Alexis Leclerc
1
Dla mnie load-external-dtdustawienie było wystarczające.
chris
Korzystanie ze wszystkich powyższych funkcji powoduje również niepowodzenie kodu. Samo użycie dwóch ostatnich funkcji (bez weryfikacji) sprawia, że ​​mój kod działa.
Purus
5

Znalazłem problem polegający na tym, że plik DTD znajdował się w pliku jar wraz z plikiem XML. Rozwiązałem problem na podstawie poniższych przykładów w następujący sposób: -

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;
         }
      }
});
Peter J.
źródło
4

Źródłowy XML (z 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>

Implementacja Java DOM do akceptowania powyższego XML jako łańcucha i usuwania deklaracji 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;

}

Docelowy XML (bez DTD)

<MYACCSERVICE>
   <REQ_PAYLOAD>
      <ACCOUNT>1234567890</ACCOUNT>
      <BRANCH>001</BRANCH>
      <CURRENCY>USD</CURRENCY>
      <TRANS_REFERENCE>201611100000777</TRANS_REFERENCE>
   </REQ_PAYLOAD>
</MYACCSERVICE> 
Shoaib Khan
źródło
2

Wiem, że nie mam dtd i nie potrzebuję go.

Jestem podejrzliwy wobec tego stwierdzenia; czy twój dokument zawiera odniesienia do encji? Jeśli tak, zdecydowanie potrzebujesz DTD.

W każdym razie, typowym sposobem zapobiegania takiej sytuacji jest użycie katalogu XML do zdefiniowania ścieżki lokalnej dla „map.dtd”.

Edward Z. Yang
źródło
2

oto inny użytkownik, który napotkał ten sam problem: http://forums.sun.com/thread.jspa?threadID=284209&forumID=34

mówi użytkownik ddssot w tym poście

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;
          }
});

Użytkownik dalej wspomina: „Jak widać, gdy parser trafia w DTD, wywoływany jest mechanizm rozpoznawania jednostek. Rozpoznaję swoje DTD z jego określonym identyfikatorem i zwracam pusty dokument XML zamiast prawdziwego DTD, zatrzymując wszystkie sprawdzanie poprawności ...”

Mam nadzieję że to pomoże.

anjanb
źródło
0

Pracuję z sonarqube, a sonarlint dla eclipse pokazał mi, że niezaufany plik XML powinien być analizowany bez rozwiązywania danych zewnętrznych (squid: S2755)

Udało mi się to rozwiązać za pomocą:

    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);
McCoy
źródło