Lassen Sie DocumentBuilder.parse DTD-Referenzen ignorieren

80

Wenn ich meine XML-Datei (Variable f) in dieser Methode analysiere, wird eine Fehlermeldung angezeigt

C: \ Dokumente und Einstellungen \ joe \ Desktop \ aicpcudev \ OnlineModule \ map.dtd (Das System kann den angegebenen Pfad nicht finden.)

Ich weiß, ich habe weder das dtd noch brauche ich es. Wie kann ich dieses Dateiobjekt in ein Dokumentobjekt analysieren, während DTD-Referenzfehler ignoriert werden?

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
quelle
1
Ich glaube, jt hat die beste Antwort auf diese Frage.
Simgineer

Antworten:

58

Ein ähnlicher Ansatz wie der von @anjanb vorgeschlagene

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

Ich habe festgestellt, dass die einfache Rückgabe einer leeren InputSource genauso gut funktioniert.

Toolkit
quelle
4
Das Festlegen der Funktionen in DocumentBuilderFactory hat bei mir funktioniert. Die Lösung in diesem Beitrag hat nicht funktioniert.
Kai Mechel
4
Dies funktionierte auch perfekt für mich, obwohl ich dachte, ich hätte SAX nicht verwendet
devnull69
Leider hat das bei mir nicht funktioniert. Ich habe immer noch den Fehler. @jt hat es für mich getan.
Nils-o-mat
Vielen Dank für die Lösung, dies ist der von org.xml empfohlene Ansatz, denke ich. Es sieht so aus, als gäbe es viel Material zu diesem Thema. siehe xerces.apache.org/xml-commons/components/resolver/… oder en.wikipedia.org/wiki/XML_Catalog und javadoc saxproject.org/apidoc/org/xml/sax/EntityResolver.html und saxproject.org/ apidoc / org / xml / sax / ext / EntityResolver2.html
aliopi
134

Versuchen Sie, Funktionen in der DocumentBuilderFactory festzulegen:

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();
...

Letztendlich denke ich, dass die Optionen spezifisch für die Parser-Implementierung sind. Hier ist eine Dokumentation für Xerces2, falls dies hilfreich ist.

jt.
quelle
21
der letzte ( load-external-dtd) hat den Trick für mich gemacht - danke.
Amarghosh
1
Beim Versuch habe ich eine DOMException erhalten: NAMESPACE_ERR: Es wird versucht, ein Objekt auf eine Weise zu erstellen oder zu ändern, die in Bezug auf Namespaces falsch ist. . Ich habe das behoben mitdbf.setNamespaceAware(true);
Tim Van Laer
Nur um Sie wissen zu lassen, funktioniert die letzte Funktionseinstellung (wie von @Amarghosh angegeben) hervorragend mit einer SAXParserFactory.
Alexis Leclerc
1
Für mich war die load-external-dtdEinstellung genug.
Chris
Wenn Sie alle oben genannten Funktionen verwenden, schlägt der Code ebenfalls fehl. Wenn ich nur die letzten beiden Funktionen verwende (nicht validierend), funktioniert mein Code.
Purus
5

Ich habe ein Problem gefunden, bei dem sich die DTD-Datei zusammen mit dem XML in der JAR-Datei befand. Ich habe das Problem anhand der folgenden Beispiele wie folgt gelöst:

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.
quelle
4

Quell-XML (mit 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-Implementierung zum Akzeptieren des obigen XML als String und Entfernen der DTD-Deklaration

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;

}

Ziel-XML (ohne DTD)

<MYACCSERVICE>
   <REQ_PAYLOAD>
      <ACCOUNT>1234567890</ACCOUNT>
      <BRANCH>001</BRANCH>
      <CURRENCY>USD</CURRENCY>
      <TRANS_REFERENCE>201611100000777</TRANS_REFERENCE>
   </REQ_PAYLOAD>
</MYACCSERVICE> 
Shoaib Khan
quelle
2

Ich weiß, ich habe weder das dtd noch brauche ich es.

Ich bin dieser Aussage misstrauisch; Enthält Ihr Dokument Entitätsreferenzen? Wenn ja, brauchen Sie auf jeden Fall die DTD.

Die übliche Methode, dies zu verhindern, ist die Verwendung eines XML-Katalogs, um einen lokalen Pfad für "map.dtd" zu definieren.

Edward Z. Yang
quelle
2

Hier ist ein anderer Benutzer, der das gleiche Problem hat: http://forums.sun.com/thread.jspa?threadID=284209&forumID=34

Benutzer ddssot auf diesem Beitrag sagt

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

Der Benutzer erwähnt weiter: "Wie Sie sehen können, wird der Entitätsauflöser aufgerufen, wenn der Parser auf die DTD trifft. Ich erkenne meine DTD mit ihrer spezifischen ID und gebe ein leeres XML-Dokument anstelle der echten DTD zurück, wodurch alle Überprüfungen gestoppt werden ..."

Hoffe das hilft.

anjanb
quelle
0

Ich arbeite mit Sonarqube und Sonarlint für Eclipse hat mir gezeigt, dass nicht vertrauenswürdiges XML analysiert werden sollte, ohne externe Daten aufzulösen (Squid: S2755).

Ich habe es geschafft, es zu lösen mit:

    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
quelle