我正在根据模式验证XML文档。一些更复杂的文档/模式在尝试使用以下代码进行验证时总是会失败:
DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
dbfac.setNamespaceAware(true);
dbfac.setIgnoringElementContentWhitespace(true);
DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
Document doc = docBuilder.parse("sampleResponse.xml");
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Source schemaSource = new StreamSource(getClass().getResourceAsStream("/" + "SampleResponse.xsd"));
Schema schema = schemaFactory.newSchema(schemaSource);
Validator validator = schema.newValidator();
Source source = new DOMSource(doc);
// Set a custom error handler that simple re-throws every exception
validator.setErrorHandler(new ValidationErrorHandler());
validator.validate(source);
问题是这一行:
Source schemaSource = new StreamSource(getClass().getResourceAsStream("/" + "SampleResponse.xsd"));
如果我将模式作为一个文件读取,它可以工作:
Source schemaSource = new StreamSource(new File("somepath/SampleResponse.xsd"));
当我直接从类路径获取模式时,为什么验证不起作用?
(在64位Windows 7上使用Java 1.6 )
失败时的异常信息:Could not validate against schema SampleResponse.xsd. Nested exception: src-resolve: Cannot resolve the name 'oa:Attachments' to a(n) 'element declaration' component.
发布于 2012-06-12 13:41:49
当您将文件传递给StreamSource时,InputStream被设置为文件的内容,但systemId也被设置为文件的URL。这允许解析模式中的相对URI。如果您的模式有任何相对URL,这肯定是您的问题。要使这些相对URL在从类路径读取模式时可解析,您需要实现一个EntityResolver。如果您不使用相对URI,那么systemId为空可能还有其他更微妙的影响。我推荐使用构造函数
StreamSource(InputStream inputStream, String systemId)
尝试将systemId设置为: null、包含架构的文件、其他文件、不存在的文件。这可能会让您对Validator正在对systemId做些什么有所了解。
发布于 2018-05-24 22:22:48
我发现我不需要实现EntityResolver来使相对URL可以从类路径解析。
将系统id设置为类路径资源的URI就足够了。
下面是一个使用Spring从类路径上的.xsd文件构建_StreamSource_s列表的工作示例。
设置验证源
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
PathMatchingResourcePatternResolver patternResolver = new PathMatchingResourcePatternResolver();
Resource[] theResources = patternResolver.getResources("classpath:schemas/**/*.xsd");
List<Source> sources = new ArrayList<>();
for (Resource resource: theResources) {
StreamSource dtd = new StreamSource(resource.getInputStream());
dtd.setSystemId(resource.getURI().toString());
sources.add(dtd);
patternResolver被赋予了一个classpath:schemas/**/*.xsd
模式,允许它递归地查找类路径上schemas目录中的所有.xsd文件。
.xsd文件可以使用相对路径导入其他.xsd文件。例如,.xsd文件可能包含如下导入:
<xsd:import namespace="urn:www.example.com/common" schemaLocation="./common.xsd">
这一行:
dtd.setSystemId(resource.getURI().toString());
是让模式验证器解析.xsd文件中的相对路径的关键。
执行验证
现在可以使用上面构建的XML数组(源)来设置StreamSource验证的模式源:
import org.xmlunit.builder.Input;
import org.xmlunit.validation.Languages;
import org.xmlunit.validation.Validator;
import javax.xml.transform.Source;
Validator v = Validator.forLanguage(Languages.W3C_XML_SCHEMA_NS_URI);
v.setSchemaSources(sources.toArray(new Source[sources.size()]));
Source input = Input.fromByteArray(xmlBytes).build();
v.validateInstance(input);
validateInstance方法调用验证由xmlBytes数组表示的XML。
发布于 2020-10-14 13:01:26
对于后人,这里是我在Scala中做的一些事情,灵感来自Joman68的答案https://stackoverflow.com/a/50518995/434405,它不使用spring库。
import javax.xml.XMLConstants
import javax.xml.transform.Source
import javax.xml.transform.stream.StreamSource
import javax.xml.validation.{Schema, SchemaFactory, Validator}
object SchemaCheck extends App {
private val xsds = List("schema.xsd") // add more as required
private val schemaDocuments: Array[Source] = xsds.map { xsd =>
val res = getClass.getResource(s"/$xsd")
val dtd = new StreamSource(res.toURI.toString)
dtd.setSystemId(res.toURI.toString)
dtd
}.toArray
private val sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI)
private val s: Schema = sf.newSchema(schemaDocuments)
private val v: Validator = s.newValidator()
private val instanceDocument: Source = new StreamSource(new java.io.File("test.xml"))
v.validate(instanceDocument)
}
https://stackoverflow.com/questions/10997453
复制相似问题