2010-03-22 11 views
12

Sono stato alla ricerca di soluzioni a questo problema per troppo tempo considerando quanto sia facile sembrare così sono venuto per un po 'di aiuto.Convalida con uno schema con JAXB

Ho uno schema XML che ho usato con xjc per creare il mio binding JAXB. Funziona bene quando l'XML è ben formato. Sfortunatamente non si lamenta anche quando l'XML non è ben formato. Non riesco a capire come fare una corretta validazione completa contro lo schema quando provo a decomprimere un file XML.

Sono riuscito a utilizzare un ValidationEventCollector per gestire gli eventi, che funziona per errori di analisi XML come tag non corrispondenti ma non genera alcun evento quando c'è un tag richiesto ma completamente assente.

Da quello che ho visto la convalida può essere eseguita di nuovo sullo schema, ma è necessario conoscere il percorso dello schema per passarlo nel metodo setSchema(). Il problema che ho è che il percorso dello schema è memorizzato nell'intestazione XML e non posso knwo in fase di esecuzione in cui lo schema sarà. Quale è il motivo per cui è memorizzato nel file XML:

<?xml version="1.0" encoding="utf-8"?> 
<DDSSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://stackoverflow.com/a/big/long/path/to/a/schema/file/DDSSettings.xsd"> 
<Field1>1</Field1> 
<Field2>-1</Field2> 

... ecc

Ogni esempio che vedo utilizza setValidating (vero), che ora è deprecato, quindi genera un'eccezione.

Questo è il codice Java che ho finora, che sembra di fare solo la validazione XML, senza schema di convalida:

try { 
    JAXBContext jc = new JAXBContext() { 
     private final JAXBContext jaxbContext = JAXBContext.newInstance("blah"); 

     @Override 
     public Unmarshaller createUnmarshaller() throws JAXBException { 
      Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); 
      ValidationEventCollector vec = new ValidationEventCollector() { 
       @Override 
       public boolean handleEvent(ValidationEvent event) throws RuntimeException { 
        ValidationEventLocator vel = event.getLocator(); 
        if (event.getSeverity() == event.ERROR || event.getSeverity() == event.FATAL_ERROR) { 
         String error = "XML Validation Exception: " + event.getMessage() + " at row: " + vel.getLineNumber() + " column: " + vel.getColumnNumber(); 
         System.out.println(error); 
        } 
        m_unmarshallingOk = false; 
        return false; 
       } 
      }; 
      unmarshaller.setEventHandler(vec); 

      return unmarshaller; 
     } 

     @Override 
     public Marshaller createMarshaller() throws JAXBException { 
      throw new UnsupportedOperationException("Not supported yet."); 
     } 

     @Override 
     @SuppressWarnings("deprecation") 
     public Validator createValidator() throws JAXBException { 
      throw new UnsupportedOperationException("Not supported yet."); 
     } 
    }; 

    Unmarshaller unmarshaller = jc.createUnmarshaller(); 
    m_ddsSettings = (com.ultra.DDSSettings)unmarshaller.unmarshal(new File(xmlfileName)); 
} catch (UnmarshalException ex) { 
    Logger.getLogger(UniversalDomainParticipant.class.getName()).log(
    Level.SEVERE, 
    null, ex); 
} catch (JAXBException ex) { 
    Logger.getLogger(UniversalDomainParticipant.class.getName()).log(
    Level.SEVERE, 
    null, ex); 
} 

Allora, qual è il modo corretto di fare questa convalida? Mi aspettavo che ci fosse un metodo validate() sulle classi generate da JAXB, ma immagino che sarebbe troppo semplice per Java.

risposta

14

OK, ho trovato la soluzione. Utilizzando lo schema factory per creare uno schema, ma senza specificare un file di schema, è possibile farlo funzionare con noNamespaceSchemaLocation specificato nel file XML.

Quindi il codice dall'alto ha avuto questo aggiunto:

SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema"); 
Schema schema = factory.newSchema(); 
Unmarshaller unmarshaller = jc.createUnmarshaller(); 
unmarshaller.setSchema(schema); 
m_ddsSettings = (com.ultra.DDSSettings)unmarshaller.unmarshal(new File(xmlfileName)); 

Peccato che ha preso la parte migliore di 24 ore per trovare la risposta a!

Il Javadoc per SchemaFactory.newSchema() dice:

Per XML Schema, questo metodo crea un oggetto schema che esegue la convalida utilizzando suggerimenti posizione specificata nel documenti.

L'oggetto dello schema restituito presuppone che se i documenti si riferiscono allo stesso URL nei suggerimenti posizione dello schema, che sempre risolvere lo stesso documento di schema . Questa impostazione consente di implementare per riutilizzare i risultati ottenuti con lo schema dei documenti dello schema in modo che le convalide multiple dello sullo stesso schema vengano eseguite più rapidamente.

+0

Interessante, non lo sapevo. Mi sono permesso di aggiungere alcune informazioni alla tua risposta, per riferimento futuro. – skaffman

+1

Invece di specificare esplicitamente l'URL XMLSchema, per javadocs, utilizzare il valore appropriato da XMLConstants come specificato qui: http://docs.oracle.com/javase/6/docs/api/index.html?javax/xml/validation /Schema.html – icfantv

+0

@icfantv, abbiamo ragione, io utilizzo: Schema schema = SchemaFactory.newInstance (XMLConstants.W3C_XML_SCHEMA_NS_URI) .newSchema(); // ma il riferimento era: http://docs.oracle.com/javase/6/docs/api/index.html?javax/xml/validation/Schema.html - Inoltre la cosa che non ho capito di questa soluzione è che l'url è costante: non si riferisce alla posizione del nostro schema (non era ovvio per me) – pdem

1

Per quanto ne so, è sufficiente impostare lo schema con Marshaller.setSchema() in uno schema creato da SchemaFactory dal proprio DDSSettings.xsd. Questo attiverà la validazione.

+0

Ma il problema è che non conosco il percorso di quel file XSD in fase di compilazione e non gli viene dato in fase di esecuzione, è memorizzato solo nell'intestazione del file XML. – fwgx

+0

Ma se si hanno classi jaxb, dovrebbero essere stati generati da uno schema. Perché non includere lo schema nel tuo progetto? –

+0

JAXB * non * ha * per lavorare con uno schema e un codice generato, funziona perfettamente senza uno schema. – skaffman

Problemi correlati