如果 XSD 作为文件或资源加载,我在 XML 验证中会遇到不同的行为。
如果我将 XSD 作为文件加载,一切都很好并且验证工作正常:
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = sf.newSchema(new ClassPathResource("my/perfect/path/myFile.xsd").getFile());
Validator validator = schema.newValidator();
validator.validate(sourceToValidate);
相反,因为我决定将 xsd 文件包含到 jar 中,所以我将其作为资源加载,但行为不同,当我构建架构时,我遇到了 SAXParseException,并且错误抱怨在解析 xsd 文件中的名称时出现一些问题:类型定义。 xsd 文件绝对正确
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("my/perfect/path/myFile.xsd");
Source schemaSource = new StreamSource(inputStream);
Schema schema = sf.newSchema(schemaSource); // here i get the SAXParseException
Validator validator = schema.newValidator();
validator.validate(sourceToValidate);
我真的不明白为什么加载 xsd 作为 ResourceAsStream 会导致不同的行为
我使用 JAXB 进行 xml 验证
我猜测您的 xsd 引用了其他 xsd,并且您的验证器不知道如何解析这些引用。
您可能需要向 Validator
提供LSResourceResolver
ClassLoader loader = getClass().getClassLoader();
LSResourceResolver resolver = new LSResourceResolver() {
public LSInput resolveResource(String type, String namespaceURI, String publicId, String systemId, String baseURI) {
InputStream stream = loader.getResourceAsStream(systemId);
if (stream == null) throw new RuntimeException("Could not find " + systemId);
LSInput input = new DOMInputImpl();
input.setPublicId(publicId);
input.setSystemId(systemId);
input.setBaseURI(baseURI);
input.setByteStream(stream);
return input;
}
};
Validator validator = schema.newValidator();
validator.setResourceResolver(resolver);
您还需要通过调用
systemId
的两个参数构造函数来设置 InputSource
上的 StreamSource
。
String xsdPath = "my/perfect/path/myFile.xsd";
InputStream inputStream = getClass().getClassLoader().getResourceAsStream(xsdPath);
Source schemaSource = new StreamSource(inputStream, xsdPath);
参见 StreamSource(InputStream, String)
除了输入流之外,此构造函数还允许设置 systemID,从而允许处理相对 URI。