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.
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:
LSResourceResolver
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;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With