2012-01-12 59 views
2

我有3個互相依賴的xsd文件來構建我的元素定義。每個xsd文件都有自己的名稱空間。當我使用JAXB xjc生成我的類時,我得到3個相應的包。到現在爲止還挺好。如何控制JAXB內存架構生成排序/序列?

我的問題出現在我想用unmarshaller進行模式驗證時。爲了避免必須讀取xsd文件,我從被解組的類中動態生成模式。但是,由於該類依賴於來自其他兩個包的對象,因此除非指定所有3個包,否則無法生成這些架構。這已經不是一個非常實用的解決方案,因爲它要求我事先知道對象層次結構/依賴關係樹,並相應地指定包列表。

當我嘗試使用SchemaFactory(SchemaFactory.newSchema(Source []))從3個生成的模式創建新模式時,我會遇到更大的問題。顯然,模式提供給模式工廠的順序對於解決依賴關係至關重要。如果數組中的第一個模式依賴於從陣列中的最後一個元素的類型定義,我得到解決的錯誤:

org.xml.sax.SAXParseException: src-resolve: Cannot resolve the name 'ns1:InCalculationDataType' to a(n) 'type definition' component. 

如果我修改的順序,先放3架構,它成功沒有錯誤。

這使得幾乎不可能編寫一個相當通用的方法,而是必須單獨爲每個XSD情況編寫代碼。

有什麼我可以做的,以緩解這個問題?有沒有辦法強制SchemaFactory首先讀取所有內容,並且只有在發現任何錯誤時纔會產生錯誤?我知道你可以創建一個ErrorHandler,但是JavaDocs指出如果它拋出一個致命錯誤,任何進一步的處理都是不可靠的。

編輯

只是我自己的心安,我試圖創建其忽略非致命錯誤(只是記錄它們),但生成的模式不可靠,無法正確驗證一個錯誤處理程序XML錯誤。因此,它對我沒有任何價值。

編輯完

任何建議或想法,將不勝感激。

謝謝!

埃裏克

+0

我記得在我的經驗,我有一個案子時'SchemaFactory.newSchema模式的順序()'事做。如果記得沒錯,那正是你得到的:一旦架構取決於其他。但是如果你想立即生成模式,你知道它們之間的依賴關係嗎? – 2012-01-13 22:59:46

+0

是的,我確實知道它們的依賴關係,但考慮到我想要在運行時生成幾個不同的xsd,我希望使用通用的一段代碼來實例化所需的class/pkg中的JAXBContext並生成模式根據其需求。但是,如果我需要手動編寫依賴關係,那麼每個XSD代必須獨立編碼,這是一種難看的解決方案,因爲我有幾個這樣的XSD /對象可以生成。 – 2012-01-14 02:26:37

回答

5

經過多次搜索,我終於找到答案。希望這會幫助別人。 StackOverflow上已經有與此問題有關的其他線程,但不知道適當的關鍵字,我沒有找到答案。

解決方案是爲模式工廠使用LSResourceResolver。即:

schemaFactory.setResourceResolver(new LSResourceResolver(){}) 

其中LSResourceResolver()負責返回XSD所需的包含/導入資源。

在SO搜索LSResourceResolver的發現一些有用的主題:https://stackoverflow.com/a/3830649/827480https://stackoverflow.com/a/2342859/827480

我會嘗試發佈自己的解決方案後,當我有更多一點的時間,但它緊隨什麼兩個已經建議上面的鏈接(通過使用字符串而不是流來簡化)。

編輯

正如所承諾的,這裏是我結束了的代碼片段:

 // get the schemas used by this class 
     final Map<String, String> schemas = new HashMap<String,String>(); 
     schemas.putAll(generateSchemas(jc)); 

     List<StreamSource> sources = new ArrayList<StreamSource>(); 
     for(String schema : schemas.values()) 
      sources.add(new StreamSource(new ByteArrayInputStream(schema.getBytes()))); 

     SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); 
     sf.setResourceResolver(new LSResourceResolver() { 
      @Override 
      public LSInput resolveResource(String type, final String namespaceURI, String publicId, String systemId, String baseURI){ 
       logger.debug("Need to resolve Resource: " + namespaceURI); 
       return new LSInput(){ 
        @Override 
        public String getStringData() { 
         // return the schema if found 
         if(schemas.containsKey(namespaceURI)){ 
          if(logger.isTraceEnabled()) 
           logger.trace("resourceResolver: Resolving schema for namespace: " + namespaceURI + schemas.get(namespaceURI)); 
          return schemas.get(namespaceURI); 
         } 
         else 
          return null; 
        } 
        @Override 
        public Reader getCharacterStream() { 
         return null; 
        } 
        @Override 
        public void setCharacterStream(Reader paramReader) { 
        } 
        @Override 
        public InputStream getByteStream() { 
         return null; 
        } 
        @Override 
        public void setByteStream(InputStream paramInputStream) { 
        } 
        @Override 
        public void setStringData(String paramString) { 
        } 
        @Override 
        public String getSystemId() { 
         return null; 
        } 
        @Override 
        public void setSystemId(String paramString) { 
        } 
        @Override 
        public String getPublicId() { 
         return null; 
        } 
        @Override 
        public void setPublicId(String paramString) { 
        } 
        @Override 
        public String getBaseURI() { 
         return null; 
        } 
        @Override 
        public void setBaseURI(String paramString) { 
        } 
        @Override 
        public String getEncoding() { 
         return null; 
        } 
        @Override 
        public void setEncoding(String paramString) { 
        } 
        @Override 
        public boolean getCertifiedText() { 
         return false; 
        } 
        @Override 
        public void setCertifiedText(boolean paramBoolean) { 
        } 
       }; 
      } 
     }); 

     // validate the schema 
     u.setSchema(sf.newSchema(sources.toArray(new StreamSource[]{}))); 

和方法generateSchemas(JC):

private Map<String, String> generateSchemas (JAXBContext jaxbContext) throws JAXBException{ 
    // generate the schemas 
    final Map<String, ByteArrayOutputStream> schemaStreams = new LinkedHashMap<String,ByteArrayOutputStream>(); 

    try { 
     jaxbContext.generateSchema(new SchemaOutputResolver(){ 
      @Override 
      public Result createOutput(String namespaceUri, String suggestedFileName) throws IOException { 
       ByteArrayOutputStream out = new ByteArrayOutputStream(); 
       logger.debug("GenerateSchemas: adding namespace: " + namespaceUri); 
       schemaStreams.put(namespaceUri, out); 
       StreamResult streamResult = new StreamResult(out); 
       streamResult.setSystemId(""); 
       return streamResult; 
      }}); 
    } catch (IOException e) { 
     // no IO being performed. Can safely ignore any IO exception. 
    } 

    // convert to a list of string 
    Map<String,String> schemas = new LinkedHashMap<String,String>(); 
    for(Map.Entry<String, ByteArrayOutputStream> entry : schemaStreams.entrySet()){ 
     String schema = entry.getValue().toString(); 
     String namespace = entry.getKey(); 
     schemas.put(namespace, schema); 
    } 

    // done 
    return schemas; 
} 

編輯完

我希望這可以幫助未來的其他人。

感謝,

埃裏克