2009-07-08 20 views
23

¿Cómo puedo validar un archivo XML con una DTD que se almacena localmente como un archivo? El archivo XML no tiene ninguna declaración DOCTYPE (o puede tener una que debe ser anulada). He echado un vistazo a this thread pero además del hecho de que están utilizando .NET dudo que esta sea una buena solución.Validar un archivo XML con un archivo DTD local con Java

¡Cualquier entrada apreciada!

Respuesta

25

En un mundo ideal, usted podría validar usando un Validator. Algo como esto:

SchemaFactory schemaFactory = SchemaFactory 
    .newInstance(XMLConstants.XML_DTD_NS_URI); 
Schema schema = schemaFactory.newSchema(new File(
    "xmlValidate.dtd")); 
Validator validator = schema.newValidator(); 
validator.validate(new StreamSource("xmlValidate.xml")); 

Desafortunadamente, la implementación de Sun (al menos, a partir de Java 6) No incluye el apoyo para la creación de una instancia de esquema de una DTD. Es posible que pueda rastrear una implementación de terceros.

Lo mejor que puede hacer es modificar el documento para incluir el DTD antes de realizar el análisis utilizando algún otro mecanismo.


Puede utilizar un transformer para insertar una declaración DTD:

TransformerFactory tf = TransformerFactory 
    .newInstance(); 
Transformer transformer = tf.newTransformer(); 
transformer.setOutputProperty(
    OutputKeys.DOCTYPE_SYSTEM, "xmlValidate.dtd"); 
transformer.transform(new StreamSource(
    "xmlValidate.xml"), new StreamResult(System.out)); 

... pero esto no parece para reemplazar una declaración DTD existente.


Este lector caso StAX puede hacer el trabajo:

public static class DTDReplacer extends 
     EventReaderDelegate { 

    private final XMLEvent dtd; 
    private boolean sendDtd = false; 

    public DTDReplacer(XMLEventReader reader, XMLEvent dtd) { 
     super(reader); 
     if (dtd.getEventType() != XMLEvent.DTD) { 
     throw new IllegalArgumentException("" + dtd); 
     } 
     this.dtd = dtd; 
    } 

    @Override 
    public XMLEvent nextEvent() throws XMLStreamException { 
     if (sendDtd) { 
     sendDtd = false; 
     return dtd; 
     } 
     XMLEvent evt = super.nextEvent(); 
     if (evt.getEventType() == XMLEvent.START_DOCUMENT) { 
     sendDtd = true; 
     } else if (evt.getEventType() == XMLEvent.DTD) { 
     // discard old DTD 
     return super.nextEvent(); 
     } 
     return evt; 
    } 

    } 

Se enviará una declaración DTD dado justo después del inicio del documento y descartar cualquier edad desde el documento.

uso Demostración:

XMLEventFactory eventFactory = XMLEventFactory.newInstance(); 
XMLEvent dtd = eventFactory 
    .createDTD("<!DOCTYPE Employee SYSTEM \"xmlValidate.dtd\">"); 

XMLInputFactory inFactory = XMLInputFactory.newInstance(); 
XMLOutputFactory outFactory = XMLOutputFactory.newInstance(); 
XMLEventReader reader = inFactory 
    .createXMLEventReader(new StreamSource(
     "xmlValidate.xml")); 
reader = new DTDReplacer(reader, dtd); 
XMLEventWriter writer = outFactory.createXMLEventWriter(System.out); 
writer.add(reader); 
writer.flush(); 

// TODO error and proper stream handling 

Tenga en cuenta que la XMLEventReader podría ser la fuente de algún otro mecanismo de transformación que lleva a cabo la validación.


Sería mucho más fácil de validar utilizando un esquema W3 si tiene esa opción.

+0

Muchas gracias por su amplia respuesta, eso realmente me ayuda mucho. Echaré un vistazo para convertir el DTD a un esquema W3, ya que puedo usar el Validator of Sun. – Simon

+0

mi archivo XML no tiene ninguna declaración DOCTYPE. y estoy analizando archivos usando SAXParser en Android. DTD generado por mí mismo. ¿Cómo puedo validar un archivo XML usando mi DTD, en el análisis SAX? –

+0

@Khushbu - sería mejor si hiciera una nueva pregunta. – McDowell

1

Tiene que implementar EntityResolver, verificar this example.

+0

Gracias por su ayuda, pero ¿y si no se ha especificado DOCTYPE en absoluto? El EntityResolver no me ayudaría en ese caso, ¿verdad? – Simon

+0

@Bluegene: ¿En qué estás validando si no hay DOCTYPE? –

+0

Contra mi propia DTD. Solo quiero asegurarme de que el XML que recibo se ajusta a _my_ DTD, no a cualquier DTD que especifique el remitente. – Simon

3

im bastante seguro de que el material antes mencionado funcionará ..

Gracias por su ayuda, pero lo que si no se ha especificado DOCTYPE en todos? El EntityResolver no me ayudaría en ese caso, ¿verdad? - Simon Jul 8 '09 a las 6:34

@Bluegene: ¿En qué estás validando si no hay DOCTYPE? - J-16 SDiZ 8 de julio '09 a las 7:12

Contra mi propia DTD. Solo quiero asegurarme de que el XML que recibo se ajusta a mi DTD, no a cualquier DTD que especifique el remitente.- Simon julio 8 '09 a 23:09

si el problema es que usted quiere que ser validado en contra de su DTD en lugar de los autores debe asegurarse de que hay una clara documentación que detalla el tipo de documento, y lo que debe estar en el archivo xml

Cuestiones relacionadas