2009-10-13 21 views
45

Necesito validar mis objetos JAXB antes de ordenar a un archivo XML. Antes de JAXB 2.0, se podía usar un javax.xml.bind.Validator. Pero eso ha sido obsoleto, así que estoy tratando de encontrar la forma adecuada de hacerlo. Estoy familiarizado con la validación en tiempo de Marshall, pero en mi caso solo quiero saber si es válida. Supongo que podría utilizar un archivo o memoria temporal y tirarlo, pero me pregunto si hay una solución más elegante.¿Cómo validar contra esquema en JAXB 2.0 sin clasificación?

Respuesta

68

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

En cuanto a su pregunta sobre la validación sin clasificación, el problema aquí es que JAXB realmente delega la validación a Xerces (o el procesador SAX que esté utilizando) y Xerces valida su documento como una secuencia de eventos SAX. Por lo tanto, para validar, debe realizar algún tipo de clasificación de.

La implementación de menor impacto de esto sería usar una implementación "/ dev/null" de un procesador SAX. La alineación con un OutputStream nulo aún implicaría la generación de XML, lo cual es un desperdicio. Así que yo 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() a tirar un JAXBException si la validación con el esquema de falla.

4

Así lo hicimos. Tenía 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 usan versiones diferentes 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); 
     } 
    } 
} 
10

Se puede usar un javax.xml.bind.util.JAXBSource (javadoc) y un javax.xml.validation.Validator (javadoc), el tiro en una implementación de org.xml.sax.ErrorHandler (javadoc) y hacer 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 más información, véase mi Blog

+2

Un problema con este enfoque: no se obtiene información del número de línea/número de columna sobre los errores de validación con este método, por lo que es difícil rastrear problemas. –

+0

¿Es ese el enfoque aplicable para Desmarcar? No puedo crear el objeto JAXBSource. – Xelian

Cuestiones relacionadas