Порядок источника JAXB SchemaFactory должен следовать порядку импорта между схемами? - PullRequest
9 голосов
/ 24 августа 2010

Использование последней версии JAXB (Sun) и иерархия схем, которые используют директивы импорта между схемами для совместного использования определений типов.Проверка схемы активируется при вызове setSchema к Marshaller / Unmarshaller в JAXB, который должен отложить проверку до Xerces (используя Java 1.5).Я не хочу знать порядок директив импорта между схемами при создании объекта Schema с SchemaFactory.К сожалению, я не нашел возможности / свойства Xerces, которые бы позволяли это.Например, если a.xsd загружается в b.xsd с помощью импорта, следующий код не работает:

FileInputStream a = new FileInputStream("a.xsd");
FileInputStream b = new FileInputStream("b.xsd");

Schema schema = SchemaFactory.newInstance(
   XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(
      new Source[] { 
          new StreamSource(b),
          new StreamSource(a) 
      }
   );

Порядок исходного массива должен быть a.xsd, а затем b.xsd.,Есть ли способ обойти это?

Ответы [ 2 ]

6 голосов
/ 24 августа 2010

Что если вы создадите схему в корневом источнике, а затем установите ResourceResolver (LSResourceResolver) для разрешения других импортированных схем во время создания схемы.

4 голосов
/ 30 сентября 2010

Поздняя публикация кода.

Создание схемы проверки с помощью:

SchemaFactory factory = SchemaFactory
.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
factory.setResourceResolver(new SimpleResolver(streams));
....
Schema schemaGrammers = factory.newSchema(streams.toArray(new SchemaSource[0]));

Схема (объект schemaGrammers) вставляется в маршаллера:

Marshaller m = ...createMarshaller();
m.setSchema(<schemaGrammers>);

И SimpleResolver реализует класс LSResourceResolver:

private class SimpleResolver implements LSResourceResolver {

    private Set<Source> streams;

    public SimpleResolver(Set<Source> streams) {
        this.streams = streams;
    }

    @Override
    public LSInput resolveResource(String type, String namespaceURI,
            String publicId, String systemId, String baseURI) {
        DOMImplementationRegistry registry;
        try {

            registry = DOMImplementationRegistry.newInstance();
            DOMImplementationLS domImplementationLS = (DOMImplementationLS) registry
                    .getDOMImplementation("LS 3.0");

            LSInput ret = domImplementationLS.createLSInput();

            for (Source source : streams) {
                SchemaSource schema = (SchemaSource) source;
                if (schema.getResourceName().equals(
                        schema.getResourceName(systemId))
                        & schema.getTargetNamespace().equals(namespaceURI)) {
                    logger.debug(
                            "Resolved systemid [{}] with namespace [{}]",
                            schema.getResourceName(systemId), namespaceURI);

                    URL url = new URL(schema.getSystemId());
                    URLConnection uc = url.openConnection();

                    ret.setByteStream(uc.getInputStream());
                    ret.setSystemId(systemId);
                    return ret;
                }
            }

        } catch (ClassCastException e) {
            logger.error(e.getMessage());
        } catch (ClassNotFoundException e) {
            logger.error(e.getMessage());
        } catch (InstantiationException e) {
            logger.error(e.getMessage());
        } catch (IllegalAccessException e) {
            logger.error(e.getMessage());
        } catch (FileNotFoundException e) {
            logger.error(e.getMessage());
        } catch (IOException e) {
            logger.error(e.getMessage());
        }

        logger.error("No stream found for system id [{}]", systemId);
        return null;
    }

}

В противном случае должен быть создан новый входной поток.Не уверен, почему (не удосужился отладить код), но потоки, которые я передаю в конструктор [т.е.объект Set] уже прочитан.

...