Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing LSResourceResolver for reading set of XSD recursively

Tags:

java

xml

xsd

I need to load XSD files from jar, so implemented LSResourceResolver as follows:

        Source schemaFile = new StreamSource(getClass().getClassLoader().getResourceAsStream("resources/xsd/root/maindoc/MainSchema.xsd"));
        SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        schemaFactory.setResourceResolver(new LSResourceResolver(){
            @Override
            public LSInput resolveResource(String type, String namespaceURI, String publicId, String systemId, String baseURI) {
                    LSInput input = new DOMInputImpl();
                String filePath = getNormalizedPath("resources/xsd/root/maindoc/", systemId);
                InputStream stream = getClass().getClassLoader().getResourceAsStream(filePath);
                input.setPublicId(publicId);
                input.setSystemId(systemId);
                input.setBaseURI(baseURI);
                input.setCharacterStream(new InputStreamReader(stream));             
                return input;
            }

        });         
        Schema schema = schemaFactory.newSchema(schemaFile); 

Such implementation successfully resolves links from the main schema, but fails to resolve links from referenced documents.

With a call from referenced document I receive not null baseURI parameter, but it's value is like "file:///var/xxx/yyy.xsd" in my case, so it does not look possible to construct a valid path from this and systemId.

Am I missing something? Should it be possible to make resolver work recursively?

Surely there is a workaround with flattening the schema, but I don't like it much.

like image 473
user3714601 Avatar asked May 19 '15 11:05

user3714601


1 Answers

Consider using method newSchema(URL schema).

I've just had a similar problem and implementing LSResourceResolver seems like too much trouble. Just take a look at this answer. I have no idea if it handles recursive includes, but it definitely looks too complicated for such a simple task.

I've found this article. It's quite old but the general idea is still valid: it's often better to use URL than InputStream for schema reading.

Advantages of using URL interface:

  • Simple construction from files and resources without custom LSResourceResolver
  • Buffering is handled by implementation.

You can't (gracefully) use this interface to read schema from a real stream (standard input or network connection). It is obviously supposed to be done with the stream interfaces. But I guess that most applications actually read schema from the host file system or application resources.

Example:

java.net.URL url = getClass().getResource("resources/main.xsd");
SchemaFactory schemaFactory = SchemaFactory.newInstance(
    XMLConstants.W3C_XML_SCHEMA_NS_URI);
schemaFactory.setErrorHandler(new CustomErrorHandler());
try {
    schema = schemaFactory.newSchema(url);
} catch (SAXException e) {
    //...
}

Note the custom error handler. For some reason Xerces emits just a warning for a missing include file. To make it throw an exception implement a handler like this:

class CustomErrorHandler implements ErrorHandler {

    public void fatalError(SAXParseException e) throws SAXException {
        throw e;
    }

    public void error(SAXParseException e) throws SAXException {
        throw e;
    }

    public void warning(SAXParseException e) throws SAXException {
        throw e;
    }

}
like image 124
and Avatar answered Nov 04 '22 13:11

and