¿Cómo leer bien formado XML en Java, pero omita el esquema?

Quiero leer un archivo XML que tenga una statement de esquema en él.

Y eso es todo lo que quiero hacer, léelo. No me importa si es válido, pero quiero que esté bien formado.

El problema es que el lector intenta leer el archivo de esquema y falla.

No quiero ni siquiera intentarlo.

Intenté deshabilitar la validación, pero todavía insiste en intentar leer el archivo de esquema.

Idealmente, me gustaría hacer esto con un inventario de Java 5 JDK.

Esto es lo que tengo hasta ahora, muy simple:

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setValidating(false); DocumentBuilder db = dbf.newDocumentBuilder(); Document doc = db.parse(file); 

y aquí está la excepción que estoy recibiendo:

 java.lang.RuntimeException: java.io.IOException: Server returned HTTP response code: 503 for URL: http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd 

Sí, esto SUCEDE a ser un esquema XHTML, pero este no es un problema “XHTML”, es un problema XML. Solo señalando eso para que la gente no se distraiga. Y, en este caso, el W3C básicamente dice “no pidas esto, es una idea tonta”, y estoy de acuerdo. Pero, de nuevo, es un detalle del problema, no la raíz del problema. No quiero pedirlo EN ABSOLUTO.

La referencia no es para Schema , sino para una DTD .

Los archivos DTD pueden contener más que solo reglas estructurales. También pueden contener referencias de entidades. Los analizadores XML están obligados a cargar y analizar referencias de DTD, porque podrían contener referencias de entidades que podrían afectar la forma en que se analiza el documento y el contenido del archivo (podría tener una referencia de entidad para caracteres o incluso frases enteras de texto).

Si desea evitar cargar y analizar la DTD referenciada, puede proporcionar su propio EntityResolver y probar la DTD referenciada y decidir si carga una copia local del archivo DTD o simplemente devuelve nulo.

Ejemplo de código de la respuesta referenciada en EntityResolvers personalizados:

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

La respuesta más simple es este one-liner, llamado después de crear DocumentBuilderFactory:

 dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); 

Descaradamente descifrado de Make DocumentBuilder.parse ignorar las referencias de DTD .

El problema aquí no es de validación. Independientemente de la configuración de validación, el analizador intentará resolver cualquier referencia en su documento, como entidades, DTD y (a veces) esquemas. Solo más tarde decide validar su uso (o no). Necesita conectar un resolvedor de entidad para “interceptar” estos bashs de eliminación de referencias.

Consulte Apache XML Resolver para obtener una forma fácil (ish) de hacerlo.

No probé esto, pero podrías intentar llamar a setSchema en la fábrica pasando null.

es decir

 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setValidating(false); dbf.setSchema(null); DocumentBuilder db = dbf.newDocumentBuilder(); Document doc = db.parse(file); 

Actualización: mirando DocumentBuilderImpl parece que esto podría funcionar, desde el constructor comprobará la gramática de fábrica antes de verificar el esquema.

De DocumentBuilderFactoryImpl:

 public void setSchema(Schema grammar) { this.grammar = grammar; } 

Del constructor DocumentBuilderImpl:

 ... this.grammar = dbf.getSchema(); if (grammar != null) { XMLParserConfiguration config = domParser.getXMLParserConfiguration(); XMLComponent validatorComponent = null; /** For Xerces grammars, use built-in schema validator. **/ ... }