我遇到了Java XML验证API的问题。当一组XSD(模式文件)传递给方法 javax.xml.validation.SchemaFactory.newSchema(Source []模式)时,它会抛出以下异常:
org.xml.sax.SAXParseException; src-resolve: Cannot resolve the name 'Report' to a(n) 'type definition' component.
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:198)
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(ErrorHandlerWrapper.java:134)
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:396)
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:306)
at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.reportSchemaErr(XSDHandler.java:4162)
at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.reportSchemaError(XSDHandler.java:4141)
at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.getGlobalDecl(XSDHandler.java:1674)
at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDElementTraverser.traverseNamedElement(XSDElementTraverser.java:405)
at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDElementTraverser.traverseGlobal(XSDElementTraverser.java:242)
at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.traverseSchemas(XSDHandler.java:1429)
at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.parseSchema(XSDHandler.java:626)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadSchema(XMLSchemaLoader.java:613)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadGrammar(XMLSchemaLoader.java:572)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadGrammar(XMLSchemaLoader.java:538)
at com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory.newSchema(XMLSchemaFactory.java:252)
...
下面显示了用于生成架构的部分代码。
public static Object converToObject(byte[] xmlByteBuffer, int offset, int length, Class<?>... type) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(type);
final List<DOMResult> results = new ArrayList<DOMResult>();
try {
context.generateSchema(new SchemaOutputResolver() {
@Override
public Result createOutput(String namespaceUri, String suggestedFileName) throws IOException {
DOMResult result = new DOMResult();
result.setSystemId(suggestedFileName);
results.add(result);
return result;
}
});
} catch (IOException e1) {
e1.printStackTrace();
}
final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
DOMSource[] sources = new DOMSource[results.size()];
for (int i = 0; i < results.size(); i++) {
DOMResult result = results.get(i);
Node node = result.getNode();
sources[i] = new DOMSource(node);
}
// First Solution: Reverse Order
// DOMSource[] resortedSources = new DOMSource[results.size()];
// for(int i=1; i<results.size(); i++){
// sourcesSorted[results.size()-(i+1)] = sources[i];
// }
// Second Solution: Look for the XSD with imports with namespace
// attribute
for (int i = 0; i < results.size(); i++) {
Node node = sources[i].getNode();
if(thereIsElementImportWithAttributeNamespace(node)) {
DOMSource sourceBackup = sources[0];
sources[0] = sources[i];
sources[i] = sourceBackup;
break;
}
}
Schema schema = null;
try {
schema = schemaFactory.newSchema(sources);
// schema = schemaFactory.newSchema(resortedSources);
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Unmarshaller unmarshaller = context.createUnmarshaller();
unmarshaller.setSchema(schema);
unmarshaller.setEventHandler(new javax.xml.bind.helpers.DefaultValidationEventHandler());
String str;
try {
str = new String(xmlByteBuffer, offset, length, "UTF-8");
} catch (UnsupportedEncodingException uee) {
try {
str = new String(xmlByteBuffer, "ISO-8859-1");
} catch (UnsupportedEncodingException ex) {
throw new JAXBException(ex);
}
}
StreamSource ss = new StreamSource(new StringReader(str));
Object obj = unmarshaller.unmarshal(ss);
return obj;
}
下面显示了传递给方法 newSchema 的真实XSD的打印部分。
schema1.xsd:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://service.mw.uw/" version="1.0">
<xs:import schemaLocation="schema4.xsd"/>
<xs:element name="Report" type="Report"/>
...
</xs:schema>
schema2.xsd:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://service.gather.mw.uw/" version="1.0">
<xs:import schemaLocation="schema4.xsd"/>
<xs:element name="DataReport" type="DataReport"/>
...
</xs:schema>
schema3.xsd:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://service.commons.uw/" targetNamespace="http://service.commons.uw/" version="1.0">
<xs:import schemaLocation="schema4.xsd"/>
<xs:element name="ApplicationRequest" type="ApplicationRequest"/>
...
</xs:schema>
schema4.xsd:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ns1="http://service.commons.uw/" xmlns:ns2="http://service.gather.mw.uw/" version="1.0">
<xs:import namespace="http://service.commons.uw/" schemaLocation="schema3.xsd"/>
<xs:import namespace="http://service.gather.mw.uw/" schemaLocation="schema2.xsd"/>
<xs:complexType name="message">
...
</xs:complexType>
...
</xs:schema>
国外传播 SchemaFactory.newSchema 无法处理导入多个XSD的多个XSD。
根据Hedleys,解决方案是在实际导入XSD之前,使用导入的XSD对任何XSD数组进行排序。我遇到了这个解决方案的问题,因为在我的项目中,XSD之间有几个相互导入。那怎么可以排序呢?
此外,根据jtahlborn,另一种解决方案是以相反的顺序使用XSD阵列。这工作得很好!但是,我一直在研究这个问题,因为在那个时候,我只有几个不同的案例来测试这个解决方案是否足够通用!
方法 SchemaFactory.newSchema 的Java文档声明如下:“XML Schema建议的第4.2.3节描述了处理器在这方面的选项。虽然处理器应该在其中保持一致处理JAXP模式源和XML模式导入时,JAXP兼容解析器之间的行为可能会有所不同;特别是,无论schemaLocation中提供的信息如何,解析器都可以选择忽略除给定命名空间的第一个之外的所有命令 ”。因此,基于该语句,我可以通过将包含namespace属性的导入的XSD放置在XSD阵列的第一个位置来解决早期提到的异常。最后,我的问题出现了:
是从XSD数组中读取的第一个XSD的导入中是否存在异常的原因?
我只能用几个不同的案例测试最后的解决方案,但一切都运行得很好!如果有人有更多的测试用例可以尝试,请让我们知道最后一个解决方案是否真的有效。
答案 0 :(得分:0)
我在任何这些架构文档中都没有看到名为Report(无命名空间)的类型,因此错误消息对我来说似乎完全合法。