web-dev-qa-db-fra.com

Faire en sorte que DocumentBuilder.parse ignore les références DTD

Lorsque j'analyse mon fichier xml (variable f) dans cette méthode, j'obtiens une erreur

C:\Documents and Settings\joe\Desktop\aicpcudev\OnlineModule\map.dtd (le système ne peut pas trouver le chemin spécifié)

Je sais que je n'ai pas le dtd et que je n'en ai pas besoin. Comment puis-je analyser cet objet File dans un objet Document tout en ignorant les erreurs de référence 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;
}
76
joe

Une approche similaire à celle suggérée par @ 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;
            }
        }
    });

J'ai trouvé que le simple retour d'un InputSource vide fonctionnait aussi bien?

57
toolkit

Essayez de définir des fonctionnalités sur 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();
...

En fin de compte, je pense que les options sont spécifiques à la mise en œuvre de l'analyseur. Voici une documentation pour Xerces2 si cela aide.

125
jt.

J'ai trouvé un problème où le fichier DTD était dans le fichier jar avec le XML. J'ai résolu le problème sur la base des exemples ici, comme suit: -

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;
         }
      }
});
5
Peter J

XML source (avec 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>

Implémentation Java DOM pour accepter le XML ci-dessus en tant que chaîne et supprimer la déclaration 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 de destination (sans DTD)

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

voici un autre utilisateur qui a eu le même problème: http://forums.Sun.com/thread.jspa?threadID=284209&forumID=34

l'utilisateur ddssot sur ce poste dit

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

L'utilisateur mentionne en outre "Comme vous pouvez le voir, lorsque l'analyseur atteint la DTD, le résolveur d'entité est appelé. Je reconnais ma DTD avec son ID spécifique et renvoie un document XML vide au lieu de la vraie DTD, arrêtant toute validation ..."

J'espère que cela t'aides.

2
anjanb

Je sais que je n'ai pas le dtd et que je n'en ai pas besoin.

Je me méfie de cette déclaration; votre document contient-il des références d'entité? Si c'est le cas, vous avez certainement besoin de la DTD.

Quoi qu'il en soit, la manière habituelle d'empêcher que cela se produise est d'utiliser un catalogue XML pour définir un chemin local pour "map.dtd".

2
Edward Z. Yang