我正在生成一些需要符合给我的xsd文件的xml文件.什么是验证它们符合要求的最佳方法?
我正在尝试将一个相当复杂的XML模式解析为Java中的Schema对象,因此我可以对XML消息进行一些验证.
我的代码看起来类似于:
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = factory.newSchema(new StreamSource(new File("schema/schema.xsd")));
Run Code Online (Sandbox Code Playgroud)
我的架构有很多导入:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="base_1">
<xs:import namespace="base_1" schemaLocation="common/MessageBase.xsd"/>
</xs:schema>Run Code Online (Sandbox Code Playgroud)
...等等.当我尝试加载架构时,我遇到了很多错误.基于与此相关的另一个问题,看起来我需要指定一个资源解析器,但这不是应该默认处理的东西吗?
如果是这样,是否有一个特定的目录,我需要将模式放在相对于我正在编写的应用程序或相对于基础模式文件的位置?
最后,当我使用XMLSpy或类似方法加载模式时,它工作正常,我可以毫无问题地验证XML实例.
如何针对包含没有架构位置的导入的XSD架构验证XML?
XSD的片段:
<xs:schema xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types
xmlns:tns="http://schemas.microsoft.com/exchange/services/2006/types"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://schemas.microsoft.com/exchange/services/2006/types"
elementFormDefault="qualified" version="Exchange2010_SP2" id="types">
<xs:import namespace="http://www.w3.org/XML/1998/namespace"/>
...
Run Code Online (Sandbox Code Playgroud)
已经阅读并尝试过:
无法从架构中删除此导入,因为它包含xml:lang属性的引用.
在变量1中使用systemId = null触发的ResourceResolver resolveResource方法
public class ResourceResolver implements LSResourceResolver {
public LSInput resolveResource(String type, String namespaceURI,
String publicId, String systemId, String baseURI) {
//Some implementation
return new Input(publicId, systemId, resourceAsStream);
Run Code Online (Sandbox Code Playgroud)
在变体2中尝试这样:
SchemaFactory sFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
//sFactory.setResourceResolver(new ResourceResolver());
Schema schema = sFactory.newSchema(new Source[] {
new StreamSource("http://www.w3.org/XML/1998/namespace"),
new StreamSource(MailGateMQBinding.class.getResourceAsStream("/types.xsd")),
});
validator = messageSchema.newValidator();
source = new DOMSource(inDocBody);
validator.validate(source); …Run Code Online (Sandbox Code Playgroud) 我需要从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);
Run Code Online (Sandbox Code Playgroud)
此类实现成功解析了主模式中的链接,但无法解析引用文档中的链接.
通过引用文档的调用,我收到的不是null的baseURI参数,但是在我的情况下它的值就像是"file:///var/xxx/yyy.xsd",所以看起来不可能从这个构造一个有效的路径的systenId.
我错过了什么吗?是否可以递归地使解析器工作?
当然有一种解决方法可以展平架构,但我不太喜欢它.
我有3个相互依赖的xsd文件来构建我的元素定义.每个xsd文件都有自己的命名空间.当我使用JAXB xjc生成我的类时,我得到3个相应的包.到现在为止还挺好.
当我想用unmarshaller进行模式验证时,我的问题出现了.为了避免必须读入xsd文件,我会从有问题的类中动态生成模式.但是,由于该类依赖于来自其他2个包的对象,因此除非我指定所有3个包,否则它无法生成模式.这已经不是一个非常实用的解决方案了,因为它要求我提前知道对象层次结构/依赖关系树,并相应地指定包列表.
当我尝试使用SchemaFactory(SchemaFactory.newSchema(Source []))从3个生成的模式创建新模式时,我遇到了更大的问题.显然,模式提供给模式工厂的顺序对于解析依赖关系至关重要.如果数组中的第一个模式依赖于数组中最后一个元素的类型定义,则会出现一个解决错误:
org.xml.sax.SAXParseException: src-resolve: Cannot resolve the name 'ns1:InCalculationDataType' to a(n) 'type definition' component.
Run Code Online (Sandbox Code Playgroud)
如果我修改顺序,并将第3个模式放在第一位,它就会成功而不会出错.
这使得编写一种相当通用的方法几乎是不可能的,而是必须单独为每个XSD案例编写代码.
我能做些什么来缓解这个问题吗?是否有某种方法可以强制SchemaFactory首先读取所有内容,然后只有在找到任何内容时才会生成错误?我知道你可以创建一个ErrorHandler,但是JavaDocs表明如果它抛出致命错误,任何进一步的处理都是不可靠的.
编辑
为了我自己的安心,我尝试创建一个错误处理程序,忽略非致命错误(只记录它们),但是生成的模式不可靠,无法正确验证xml错误.因此,它对我没有任何价值.
结束编辑
任何建议或想法将不胜感激.
谢谢!
埃里克