Pregunta

Cuando analizo mi archivo xml (variable f) en este método, aparece un error

  

C: \ Documents and Settings \ joe \ Desktop \ aicpcudev \ OnlineModule \ map.dtd (El sistema no puede encontrar la ruta especificada)

Sé que no tengo el dtd, ni lo necesito. ¿Cómo puedo analizar este objeto de archivo en un objeto de documento sin tener en cuenta los errores de referencia de 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;
}
¿Fue útil?

Solución

Un enfoque similar al sugerido por @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;
            }
        }
    });

Encontré que simplemente devolver un InputSource vacío funcionó igual de bien?

Otros consejos

Intente configurar las características en 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 última instancia, creo que las opciones son específicas para la implementación del analizador. Aquí hay alguna documentación para Xerces2 si eso ayuda.

Encontré un problema donde el archivo DTD estaba en el archivo jar junto con el XML. Resolví el problema basándose en los ejemplos que se incluyen a continuación: -

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

Sé que no tengo el dtd, ni lo necesito.

Sospecho de esta afirmación; ¿Su documento contiene alguna referencia de entidad? Si es así, definitivamente necesitas el DTD.

De todos modos, la forma habitual de evitar que esto suceda es utilizar un catálogo XML para definir una ruta local para " map.dtd " ;.

aquí hay otro usuario que tuvo el mismo problema: http: // foros. sun.com/thread.jspa?threadID=284209&forumID=34

el usuario ddssot en esa publicación dice

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

El usuario menciona además " Como puede ver, cuando el analizador golpea el DTD, se llama al resolvedor de entidades. Reconozco mi DTD con su ID específica y devuelvo un documento XML vacío en lugar del DTD real, deteniendo toda validación ... "

Espero que esto ayude.

XML de origen (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>

Implementación de Java DOM para aceptar XML anterior como cadena y eliminar declaración 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;

}

Destino XML (sin DTD)

<MYACCSERVICE>
   <REQ_PAYLOAD>
      <ACCOUNT>1234567890</ACCOUNT>
      <BRANCH>001</BRANCH>
      <CURRENCY>USD</CURRENCY>
      <TRANS_REFERENCE>201611100000777</TRANS_REFERENCE>
   </REQ_PAYLOAD>
</MYACCSERVICE> 
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top