Domanda

Quando analizzo il mio file xml (variabile f) in questo metodo, ottengo un errore

  

C: \ Documents and Settings \ joe \ Desktop \ aicpcudev \ OnlineModule \ map.dtd (il sistema non riesce a trovare il percorso specificato)

So di non avere il dtd, né ne ho bisogno. Come posso analizzare questo oggetto File in un oggetto Document ignorando gli errori di riferimento 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;
}
È stato utile?

Soluzione

Un approccio simile a quello suggerito da @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;
            }
        }
    });

Ho scoperto che anche semplicemente restituire un InputSource vuoto ha funzionato altrettanto bene?

Altri suggerimenti

Prova a impostare le funzionalità su 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();
...

In definitiva, penso che le opzioni siano specifiche per l'implementazione del parser. Ecco alcuni documenti per Xerces2 se ciò aiuta.

Ho riscontrato un problema in cui il file DTD si trovava nel file jar insieme a XML. Ho risolto il problema basandomi sugli esempi qui di seguito, come segue: -

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

So di non avere il dtd, né ne ho bisogno.

Sono sospettoso di questa affermazione; il tuo documento contiene riferimenti a entità? In tal caso, hai sicuramente bisogno del DTD.

Comunque, il solito modo per evitare che ciò accada è usare un catalogo XML per definire un percorso locale per " map.dtd " ;.

ecco un altro utente che ha riscontrato lo stesso problema: http: // forum. sun.com/thread.jspa?threadID=284209&forumID=34

dice l'utente ddssot su quel post

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'utente menziona inoltre " Come puoi vedere, quando il parser colpisce il DTD, viene chiamato il risolutore di entità. Riconosco il mio DTD con il suo ID specifico e restituisco un documento XML vuoto invece del vero DTD, interrompendo tutta la convalida ... "

Spero che questo aiuti.

XML di origine (con 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>

Implementazione DOM Java per accettare sopra XML come stringa e rimuovere la dichiarazione 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 di destinazione (senza DTD)

<MYACCSERVICE>
   <REQ_PAYLOAD>
      <ACCOUNT>1234567890</ACCOUNT>
      <BRANCH>001</BRANCH>
      <CURRENCY>USD</CURRENCY>
      <TRANS_REFERENCE>201611100000777</TRANS_REFERENCE>
   </REQ_PAYLOAD>
</MYACCSERVICE> 
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top