¿Cómo validar contra esquema en JAXB 2.0 sin marshalling?


Necesito validar mis objetos JAXB antes de usar un archivo XML. Antes de JAXB 2.0, se podía usar un javax.XML.unir.Validador. Pero eso ha sido obsoleto, así que estoy tratando de averiguar la forma correcta de hacer esto. Estoy familiarizado con la validación en el tiempo marshall, pero en mi caso solo quiero saber si es válido. Supongo que podría ordenar a un archivo temporal o memoria y tirarlo a la basura, pero me pregunto si hay una solución más elegante.

 46
Author: skaffman, 2009-10-13

3 answers

En primer lugar, javax.xml.bind.Validator ha sido obsoleto a favor de javax.xml.validation.Schema (javadoc ). La idea es que analice su esquema a través de un javax.xml.validation.SchemaFactory (javadoc ), e inyecta eso en el marshaller/unmarshaller.

En cuanto a su pregunta con respecto a la validación sin marshalling, el problema aquí es que JAXB realmente delega la validación a Xerces (o cualquier procesador de SAXO que esté utilizando), y Xerces valida su documento como un flujo de eventos de SAXO. Así que con el fin de validar, es necesario realizar algunos tipo de marshalling.

La implementación de menor impacto de esto sería usar una implementación "/dev/null" de un procesador SAX. El marshalling a un OutputStream nulo aún implicaría la generación de XML, lo cual es un desperdicio. Así que sugeriría:

SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema(locationOfMySchema); 

Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setSchema(schema);
marshaller.marshal(objectToMarshal, new DefaultHandler());

DefaultHandler descartará todos los eventos, y la operación marshal() lanzará una excepción JAXBException si falla la validación contra el esquema.

 71
Author: skaffman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-08 09:37:07

Podrías usar un javax.xml.bind.util.JAXBSource (javadoc ) y a javax.xml.validation.Validator (javadoc ), lanzar una implementación de org.xml.sax.ErrorHandler (javadoc ) y haga lo siguiente:

import java.io.File;

import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.util.JAXBSource;
import javax.xml.validation.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        Customer customer = new Customer();
        customer.setName("Jane Doe");
        customer.getPhoneNumbers().add(new PhoneNumber());
        customer.getPhoneNumbers().add(new PhoneNumber());
        customer.getPhoneNumbers().add(new PhoneNumber());

        JAXBContext jc = JAXBContext.newInstance(Customer.class);
        JAXBSource source = new JAXBSource(jc, customer);

        SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); 
        Schema schema = sf.newSchema(new File("customer.xsd")); 

        Validator validator = schema.newValidator();
        validator.setErrorHandler(new MyErrorHandler());
        validator.validate(source);
    }

}

Para Obtener Más Información, Consulte Mi Blog

 11
Author: Blaise Doughan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-08 10:57:21

Así lo hicimos. Tuve que encontrar una manera de validar el archivo xml frente a un xsd correspondiente a la versión del xml, ya que tenemos muchas aplicaciones que utilizan diferentes versiones del contenido xml.

Realmente no encontré ningún buen ejemplo en la red y finalmente terminé con esto. Espero que esto ayude.

ValidationEventCollector vec = new ValidationEventCollector();

SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);

URL xsdURL = getClass().getResource("/xsd/" + xsd);
Schema schema = sf.newSchema(xsdURL);

//You should change your jaxbContext here for your stuff....
Unmarshaller um = (getJAXBContext(NotificationReponseEnum.NOTIFICATION, notificationWrapper.getEnteteNotification().getTypeNotification()))
    .createUnmarshaller();
um.setSchema(schema);

try {
    StringReader reader = new StringReader(xml);
    um.setEventHandler(vec);
    um.unmarshal(reader);
} catch (javax.xml.bind.UnmarshalException ex) {
    if (vec != null && vec.hasEvents()) {
        erreurs = new ArrayList < MessageErreur > ();
        for (ValidationEvent ve: vec.getEvents()) {
            MessageErreur erreur = new MessageErreur();
            String msg = ve.getMessage();
            ValidationEventLocator vel = ve.getLocator();
            int numLigne = vel.getLineNumber();
            int numColonne = vel.getColumnNumber();
            erreur.setMessage(msg);
            msgErreur.setCode(ve.getSeverity())
            erreur.setException(ve.getLinkedException());
            erreur.setPosition(numLigne, numColonne);
            erreurs.add(erreur);

            logger.debug("Erreur de validation xml" + "erreur : " + numLigne + "." + numColonne + ": " + msg);
        }
    }
}
 4
Author: Pat B,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-09 03:38:22