我需要从jar加载XSD文件,所以实现了LSResourceResolver,如下所示:
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);
此类实现成功解析了主模式中的链接,但无法解析引用文档中的链接。
通过引用文档的调用,我收到的不是null的baseURI参数,但在我的例子中它的值就像“file:///var/xxx/yyy.xsd”,所以看起来不可能构造一个有效的路径从这和systemId。
我错过了什么吗?是否可以递归地使解析器工作?
当然有一种解决方法可以展平架构,但我不太喜欢它。
答案 0 :(得分:6)
考虑使用方法newSchema(URL schema)
。
我遇到了类似的问题,实施LSResourceResolver
似乎太麻烦了。请看一下this answer。我不知道它是否处理递归包含,但对于这么简单的任务来说它看起来确实太复杂了。
我找到了this article。它已经很老了,但总体思路仍然有效:使用URL
而非InputStream
进行架构阅读通常会更好。
使用URL
接口的优点:
LSResourceResolver
您无法(优雅地)使用此接口从实际流(标准输入或网络连接)读取架构。显然应该使用流接口来完成。但我想大多数应用程序实际上是从主机文件系统或应用程序资源中读取模式。
示例:
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) {
//...
}
请注意自定义错误处理程序。出于某种原因,Xerces仅针对缺少的包含文件发出警告。为了使它抛出一个异常,实现一个像这样的处理程序:
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;
}
}