2010-03-22 84 views
12

我一直在尋找針對這個問題的解決方案,考慮這聽起來有多容易,所以我得到了一些幫助。使用JAXB對模式進行驗證

我有一個XML模式,我用xjc來創建我的JAXB綁定。這在XML格式正確時工作正常。不幸的是,當XML格式不正確時,它也不會抱怨。我不知道如何在嘗試解組XML文件時對模式進行適當的全面驗證。

我設法使用ValidationEventCollector來處理事件,這些事件適用於XML解析錯誤,例如不匹配的標記,但在有標記是必需但完全缺失時不會引發任何事件。

從我所看到的驗證可以針對模式完成,但是您必須知道模式的路徑才能將其傳遞到setSchema()方法中。我遇到的問題是架構的路徑存儲在XML頭中,並且在架構將要運行的時候我無法知道。這就是爲什麼它存儲在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> 

...等

每個例子中,我看到的setValidating使用(true),這是現在已經過時,所以拋出異常。

這是Java代碼,我到目前爲止,這似乎只能做XML驗證,而不是架構驗證:

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

那麼,什麼是做到這一點的驗證的正確方法?我期待在JAXB生成的類中有一個validate()方法,但我想這對於Java來說太簡單了。

回答

14

好的,我找到了解決方案。使用模式工廠創建模式,但不指定模式文件使其與XML文件中指定的noNamespaceSchemaLocation一起工作。

所以從上面的代碼中已經有了這樣說:

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

恥辱,花了24小時的最好的部分,以找到答案!

SchemaFactory.newSchema()的Javadoc說:

對於XML模式,此方法創建,通過使用在 文件中規定的位置提示執行驗證 一個 Schema對象。

返回的Schema對象假定 ,如果證件是指在架構位置提示相同 URL,他們將 始終解析到相同的架構 文件。此asusmption允許 實現重用解析的 模式文檔的結果,以便針對相同 模式的多個驗證運行得更快。

+0

有趣的是,我不知道。我冒昧給您的答案添加一些信息,以備將來參考。 – skaffman 2010-03-23 00:14:39

+1

不是根據javadocs顯式指定XMLSchema URL,而是使用XMLConstants中適當的值,如下所示:http://docs.oracle.com/javase/6/docs/api/index.html?javax/xml/validation /Schema.html – icfantv 2011-11-28 18:38:58

+0

@icfantv我們是對的,我使用:Schema schema = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema();//但參考是:http://docs.oracle.com/javase/6/docs/api/index.html?javax/xml/validation/Schema.html - 此外,我不明白這個解決方案的事情是網址是不變的:它不是指我們自己的模式的位置(對我來說不明顯) – pdem 2016-02-23 13:46:55

1

據我所知,你只需要將Marshaller.setSchema()的模式設置爲由DDSSettings.xsdSchemaFactory創建的模式。這將打開驗證。

+0

但問題是,我不知道在編譯時該XSD文件的路徑,並沒有在運行時給它 - 它只存儲在XML文件標題中。 – fwgx 2010-03-22 12:00:28

+0

但是如果你有jaxb-classes,它們應該是從模式生成的。爲什麼不把模式包含在你的項目中? – 2010-03-22 12:31:49

+0

JAXB沒有*可以使用模式和生成的代碼,它在沒有模式的情況下工作得非常好。 – skaffman 2010-03-22 22:41:40

相關問題