2009-10-13 10 views
45

Potrzebuję do sprawdzania poprawności moich obiektów JAXB przed zestawieniem do pliku XML. Przed wersją JAXB 2.0 można było użyć javax.xml.bind.Validator. Ale to jest przestarzałe, więc staram się wymyślić właściwy sposób robienia tego. Jestem zaznajomiony z walidacją w czasie marshall, ale w moim przypadku po prostu chcę wiedzieć, czy jest ważna. Przypuszczam, że mógłbym wysłać do pliku tymczasowego lub pamięci i wyrzucić go, ale zastanawiam się, czy istnieje bardziej eleganckie rozwiązanie.Jak sprawdzić poprawność w stosunku do schematu w JAXB 2.0 bez zestawiania?

Odpowiedz

68

Po pierwsze, javax.xml.bind.Validator został wycofany na rzecz javax.xml.validation.Schema (javadoc). Chodzi o to, że analizujesz swój schemat przez javax.xml.validation.SchemaFactory (javadoc) i wstrzykujesz go do marshaller/unmarshaller.

Jeśli chodzi o pytanie dotyczące sprawdzania poprawności bez zestawiania, problem polega na tym, że JAXB faktycznie deleguje walidację do Xerces (lub dowolnego procesora SAX, którego używasz), a Xerces sprawdza twój dokument jako strumień zdarzeń SAX. Aby przeprowadzić walidację, musisz wykonać rodzaj kołysania.

Najniższą implementacją tego rozwiązania byłoby użycie implementacji "/ dev/null" procesora SAX. Przekazywanie do wartości zerowej OutputStream nadal wymagałoby generowania XML, co jest marnotrawstwem. Więc proponuję:

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 anuluje wszystkie zdarzenia, a operacja marshal() rzuci JAXBException jeśli sprawdzanie poprawności przeciwko schematu nie powiedzie się.

4

To jak to zrobiliśmy. Musiałem znaleźć sposób sprawdzenia poprawności pliku xml w stosunku do xsd odpowiadającego wersji xml, ponieważ mamy wiele aplikacji używających różnych wersji zawartości xml.

Tak naprawdę nie znalazłem żadnych dobrych przykładów w sieci i ostatecznie skończyłem z tym. Mam nadzieję, że to pomoże.

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

można użyć javax.xml.bind.util.JAXBSource (javadoc) i javax.xml.validation.Validator (javadoc), rzucać w realizacji org.xml.sax.ErrorHandler (javadoc) i wykonaj następujące czynności:

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

} 

Aby uzyskać więcej informacji, zobacz moje Blog

+2

Jedna z kwestii związanych z tym podejściem: w przypadku tej metody nie można uzyskać informacji o numerze wiersza/kolumnie na temat błędów sprawdzania poprawności, dlatego trudno jest prześledzić problemy. –

+0

Czy to podejście ma zastosowanie do Unmarchalling. Nie mogę utworzyć obiektu JAXBSource. – Xelian

Powiązane problemy