90 votes

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 et paramètres \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 en 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;
}

1 votes

Je pense que jt a la meilleure réponse à cette question.

149voto

jt. Points 3116

Essayez de définir des caractéristiques sur le 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 à l'implémentation du parseur. Voici de la documentation pour Xerces2 si cela peut aider.

24 votes

Le dernier ( load-external-dtd ) a fait l'affaire pour moi - merci.

1 votes

En essayant cela, j'ai eu un DOMException : NAMESPACE_ERR : On tente de créer ou de modifier un objet d'une manière incorrecte au regard des espaces de noms. . J'ai corrigé cela avec dbf.setNamespaceAware(true);

0 votes

Juste pour vous faire savoir, le dernier paramètre de la fonctionnalité (comme indiqué par @Amarghosh) fonctionne très bien avec un SAXParserFactory.

61voto

toolkit Points 27248

Une approche similaire à celle proposé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 renvoyer simplement un InputSource vide fonctionnait tout aussi bien ?

5 votes

La configuration des fonctionnalités de DocumentBuilderFactory a fonctionné pour moi. La solution proposée dans cet article n'a pas fonctionné.

4 votes

Cela a également fonctionné parfaitement pour moi, même si je pensais ne pas utiliser SAX

0 votes

Malheureusement, cela n'a pas fonctionné pour moi. J'ai toujours l'erreur. @jt l'a fait pour moi.

6voto

Peter J Points 11

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 en me basant sur les exemples donnés 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;
         }
      }
});

2voto

Edward Z. Yang Points 13760

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

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

Quoi qu'il en soit, la façon habituelle d'empêcher cela est d'utiliser un catalogue XML pour définir un chemin local pour "map.dtd".

2voto

anjanb Points 5579

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 post 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 ajoute : "Comme vous pouvez le voir, lorsque le parseur rencontre la DTD, le résolveur d'entités est appelé. Je reconnais ma DTD avec son ID spécifique et renvoie un doc XML vide au lieu de la vraie DTD, arrêtant toute validation..."

J'espère que cela vous aidera.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X