JAXB SchemaFactory source order must follow import order between schemas?

前端 未结 2 674
慢半拍i
慢半拍i 2020-12-19 02:31

Using latest JAXB (Sun) and have a hierarchy of schemas that use import directives between schemas to share type definitions. Schema validation is activated on the setSchem

相关标签:
2条回答
  • 2020-12-19 03:03

    What if you create a schema on the root Source, and then set a ResourceResolver (LSResourceResolver) to resolve the other imported schemas during the schema creation.

    0 讨论(0)
  • 2020-12-19 03:04

    Late post of the code.

    Generate a validation Schema with:

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

    The Schema (schemaGrammers object) gets injected into the Marshaller:

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

    And the SimpleResolver implements the LSResourceResolver class:

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

    A new input stream has to be created otherwise a conflict occurs. Not sure why (didn't bother to debug the code) but the streams I pass to the constructor [ie. the Set object] have already been read.

    0 讨论(0)
提交回复
热议问题