在JAXB中,是否可以仅在解组期间验证 xsd:any 元素并且不再进行钻取?
用例是我有两个XML Schema文件,一个定义信封(在某些时候包括 xsd:any 元素),另一个定义有效载荷模式(用于 xsd:任何元素)。因为实际上可以存在许多不同类型的有效载荷 - 未来还会有更多 - 我已经构建了我的代码,以便在this SO question的答案中建议使用两步解组。
所以我有一个只在不查看有效负载的情况下解组和验证信封的库。问题在于使用JAXB我无法想象只使用setSchema
的{{1}}方法验证信封。验证失败,因为它无法找到有效负载的模式,但我无法在信封处理 jar 中添加这些模式,因为信封应该与有效负载无关。因此,我无法以与有效负载无关的方式在其自己的库中实现包络处理逻辑。
接下来是一个简单的具体例子。当代码运行时,它失败了:
Unmarshaller
[java] Caused by: org.xml.sax.SAXParseException; lineNumber: 8; columnNumber: 23; cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element 'b:person'.
<?xml version="1.0" encoding="UTF-8"?>
<schema elementFormDefault="qualified"
xmlns ="http://www.w3.org/2001/XMLSchema"
xmlns:a ="http://www.example.org/A"
targetNamespace ="http://www.example.org/A">
<element name="someType" type="a:SomeType"></element>
<complexType name="SomeType">
<sequence>
<any namespace="##other" processContents="strict"/>
</sequence>
</complexType>
</schema>
<?xml version="1.0" encoding="UTF-8"?>
<schema elementFormDefault="qualified"
xmlns ="http://www.w3.org/2001/XMLSchema"
xmlns:b ="http://www.example.org/B"
targetNamespace="http://www.example.org/B"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<element name="person" type="b:PersonType"></element>
<complexType name="PersonType">
<sequence>
<element name="firstName" type="string"/>
<element name="lastName" type="string"/>
</sequence>
</complexType>
</schema>
<?xml version="1.0" encoding="UTF-8"?>
<a:someType xmlns:a="http://www.example.org/A"
xmlns:b="http://www.example.org/B"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.example.org/A A.xsd
http://www.example.org/B B.xsd">
<b:person>
<b:firstName>Mary</b:firstName>
<b:lastName>Bones</b:lastName>
</b:person>
</a:someType>
答案 0 :(得分:1)
我无法使用JAXB实现这种部分验证。但是,使用javax.xml.validation.Validator
我是在验证外包络并在使用自定义org.xml.sax.ErrorHandler
到达有效内容元素时抑制异常。该解决方案根本不令人满意,因为它依赖于异常消息的比较以抑制异常(getColumnNumber
类的getLineNumber
和SAXParseException
方法不能用作发生错误的确切行和列不是固定的XML实例文档。)
我粘贴下面的代码,但就像我说的那样我根本不喜欢消息比较抑制逻辑,因为我必须预测所有可能的任何有效负载元素(因为元素名称出现在信息)。还有更好的方法吗?
class CustomErrorHandler implements ErrorHandler {
@Override
public void warning(SAXParseException exc) {
throw exc;
}
@Override
public void error(SAXParseException exc) throws SAXParseException {
if (exc.getMessage().equals("cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element 'b:person'."))
; // suppress
else
throw exc;
}
@Override
public void fatalError(SAXParseException exc) throws SAXParseException {
throw exc;
}
}
public class FooMain {
public static void main (String args[]) throws JAXBException, FileNotFoundException, SAXException, IOException {
String xmlFileName = "ab.xml";
final Schema SCHEMA_A = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(new File("A.xsd"));
SAXSource source = new SAXSource(new InputSource(xmlFileName));
Validator validator = SCHEMA_A.newValidator();
validator.setErrorHandler(new CustomErrorHandler());
validator.validate(source);
JAXBContext jc = JAXBContext.newInstance("example.a");
Unmarshaller u = jc.createUnmarshaller();
// u.setSchema(SCHEMA_A); // not possible to partially validate using this method
JAXBElement<SomeType> element = (JAXBElement<SomeType>) u.unmarshal( new FileInputStream( xmlFileName ) );
}
}
答案 1 :(得分:0)
匹配的通配符是严格的,但是找不到声明 元素'b:人'。
此消息表示在架构中使用processContents="strict"
(默认值)声明了任何元素。期望验证器处理任何元素的内容,但缺少元素声明b:person
。
有两种方法可以处理这种情况:
确保提供给验证程序的模式集包含b:person
元素声明 - 可以为SchemaFactory.newSchema
提供多个模式源。在这种情况下,Validator将验证完整的XML,包括任何元素的内容。
OR - 通过在您的架构中为任何元素声明指定属性processContents="lax"
或processContents="skip"
来放松内容处理规则,以便执行部分验证,如XML Schema any Element所述。在这种情况下,Validator不会验证完整的XML,也不会跳过任何元素的内容。