Haga que DocumentBuilder.parse ignore las referencias de DTD

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 File en un objeto Document mientras ignoro los errores de referencia 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; } 

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

Descubrí que simplemente devolver un InputSource vacío funcionaba igual de bien.

Intente configurar funciones 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 definitiva, creo que las opciones son específicas para la implementación del analizador. Aquí hay 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 en base a los ejemplos aquí, de la siguiente manera:

 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 statement; ¿su documento contiene referencias de entidades? Si es así, definitivamente necesitas la 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 tiene el mismo problema: http://forums.sun.com/thread.jspa?threadID=284209&forumID=34

ddssot de usuario 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 toca la DTD, se invoca la resolución de la entidad. Reconozco mi DTD con su ID específica y devuelvo un documento XML vacío en lugar de la DTD real, deteniendo toda la validación …”

Espero que esto ayude.

Fuente XML (con DTD)

 < !DOCTYPE MYSERVICE SYSTEM "./MYSERVICE.DTD">   1234567890 001 USD 201611100000777   

Implementación Java DOM para aceptar el XML anterior como Cadena y eliminar la statement 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 destino (sin DTD)

   1234567890 001 USD 201611100000777