本来这是件很简单的事情,主要代码如下:
SAXBuilder builder = new SAXBuilder("org.apache.xerces.parsers.SAXParser", true);
// set entity resolver to ignore the DTD specified in the template
builder.setEntityResolver(new EntityResolver() {
public InputSource resolveEntity(String publicId,
String systemId) throws IOException
{
//load schema here
return new InputSource(new FileInputStream(TEMPLATE_SCHEMA_FILE));
}
});
builder.setFeature("http://xml.org/sax/features/validation",true);
builder.setFeature("http://apache.org/xml/features/validation/schema", true);
builder.build(new ByteArrayInputStream(templateData));
但是最近使用的时候,却发现一个怪问题,就是在系统运行期间,用另外的schema对另外的xml文件进行验证时,总是提示schema找不到的相关错误信息。几经周折都没有发现原因,只是隐约感觉到在第一个schema对xml进行校验之后,后面的schema根本没有没加载到内存中。
后来根据这个思路,发现了原来的系统使用了Schema的cache,
System.setProperty("org.apache.xerces.xni.parser.XMLParserConfiguration",
"org.apache.xerces.parsers.XMLGrammarCachingConfiguration");
而这个cache的key是用schema中的targetNameSpace和另外一个不变的值组成的,所以在有新的schema(我的schema之前没有targetNameSpace)到来时,xerces根据通过检查cache,会发现cache已经有了,于是就不再加载新的schema,就导致,新的xml文件总是用第一次加载的那个schema进行校验。当然就出错了。解决这个问题有两个办法:
一、关闭cache,这回导致性能问题;
二、给自己的xml加上targetNameSpace:
这里分别给出xml 和schema头部需要加的内容的格式
xml: <YourXmlRootElement xmlns="http://ministone.org/schema/demo"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ministone.org/schema/demo demo.xsd">
schema: <xs:schema xmlns="http://ministone.org/schema/demo"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://ministone.org/schema/demo">
需要注意的是:xml文件中 xsi:schemaLocation="http://ministone.org/schema/demo demo.xsd" 的值是用空格隔开的字符串,第一部分是targetNameSpace,要和schema中的一致,而第二部分demo.xsd是schema文件的名称,在上面给出的示例代码中,这个值是不起作用的。
其余的items的涵义可以参看w3schools上的教程。