2012-01-12 3 views
2

У меня есть 3 файла xsd, которые зависят друг от друга, чтобы создавать определения моих элементов. Каждый xsd-файл имеет собственное пространство имен. Когда я создаю свои классы с помощью JAXB xjc, я получаю 3 соответствующих пакета. Все идет нормально.Как управлять упорядочением/последовательностью генерации схемы памяти в JAXB?

Моя проблема возникает, когда я хочу сделать проверку схемы с помощью unmarshaller. Чтобы избежать чтения в xsd-файлах, я генерирую схемы «на лету» из класса, о котором идет речь, будучи немаршарированным. Однако, поскольку класс зависит от объектов из 2 других пакетов, он не может сгенерировать схемы, если я не укажу все 3 пакета. Это уже не очень практическое решение, так как оно требует от меня знать дерево иерархии объектов/дерева зависимостей и соответственно указать список пакетов.

Моя большая проблема возникает, когда я пытаюсь создать новую схему из 3 сгенерированных схем, используя SchemaFactory (SchemaFactory.newSchema (Source [])). По-видимому, порядок, в котором схемы предоставляются на фабрике схемы, имеет решающее значение для разрешения зависимостей. Если первая схема в массиве зависит от определения типа от последнего элемента в массиве, я получаю ошибку постановляет:

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

Если я изменить порядок и поставить 3-ю схему первой, она преуспевает без ошибок ,

Это делает практически невозможным создание метода достаточно общего, но, скорее, необходимо кодировать для каждого случая XSD индивидуально.

Есть ли что-нибудь, что я могу сделать для облегчения этой проблемы? Есть ли способ заставить SchemaFactory сначала прочитать все, а затем сгенерировать его ошибки, если он найдет какие-либо? Я знаю, что вы можете создать ErrorHandler, однако JavaDocs указывают, что если он выдает Fatal-ошибку, любая дальнейшая обработка ненадежна.

EDIT

Просто для моего собственного спокойствия, я попытался создать обработчик ошибок, который игнорировал не фатальные ошибки (только зарегистрированным их), однако генерируемый схема была ненадежной и не удалось должным образом проверить xml ошибки. Следовательно, это не имело значения для меня.

END EDIT

Любые предложения или мысли будут оценены.

Спасибо!

Эрик

+0

Я помню, в моем опыте у меня был случай, когда порядок схем в 'SchemaFactory.newSchema()' сделал дело. И если правильно помнить, это было именно то, что вы получили: когда схема была в зависимости от другой. Но если вы хотите генерировать схемы «на лету», вы знаете зависимость между ними? –

+0

Да, я знаю их зависимости, но учитывая, что есть несколько разных xsds, которые я хочу генерировать «на лету», я надеялся использовать общий фрагмент кода, который создавал JAXBContext из требуемого класса/pkg и генерировал схему исходя из его потребностей. Однако, если мне нужно закодировать зависимости вручную, то каждое поколение XSD должно быть закодировано независимо, что несколько уродливое решение, учитывая, что у меня есть несколько таких XSD/объектов для генерации. –

ответ

5

После долгих поисков я наконец нашел ответ. Надеюсь, это поможет кому-то другому. В StackOverflow уже есть другие темы, связанные с этой проблемой, но, не зная правильных ключевых слов, я не нашел ответов.

Решение заключается в использовании LSResourceResolver для фабрики схем. то есть:

schemaFactory.setResourceResolver(new LSResourceResolver(){}) 

где LSResourceResolver() отвечает за возвращение включения/ресурс импорта, который требуется в XSD.

Поиск LSResourceResolver в SO нашел несколько полезных темы: https://stackoverflow.com/a/3830649/827480, https://stackoverflow.com/a/2342859/827480

Постараюсь опубликовать свое собственное решение позже, когда у меня есть немного больше времени, но он внимательно следит за того, что уже было предложено в два над ссылками (шахта немного упрощена, используя строки вместо потоков ...).

EDIT

Как и было обещано, вот фрагмент кода, который я закончил с:

 // 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 (х):

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

END EDIT

Надеюсь, это поможет кому-то еще в будущем.

Спасибо,

Эрик

Смежные вопросы