使用 JAXB 验证架构
考虑到这听起来很容易,我一直在寻找这个问题的解决方案,所以我来寻求帮助。
我有一个 XML 架构,我已将其与 xjc 一起使用来创建 JAXB 绑定。当 XML 格式良好时,此方法可以正常工作。不幸的是,当 XML 格式不正确时,它也不会抱怨。当我尝试解组 XML 文件时,我无法弄清楚如何针对架构进行正确的完整验证。
我设法使用 ValidationEventCollector 来处理事件,它适用于 XML 解析错误(例如标签不匹配),但当存在需要但完全不存在的标签时,不会引发任何事件。
据我所知,可以针对模式进行验证,但您必须知道模式的路径才能将其传递到 setSchema() 方法中。我遇到的问题是架构的路径存储在 XML 标头中,并且我在运行时无法知道架构的位置。这就是它存储在 XML 文件中的原因:
<?xml version="1.0" encoding="utf-8"?>
<DDSSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="/a/big/long/path/to/a/schema/file/DDSSettings.xsd">
<Field1>1</Field1>
<Field2>-1</Field2>
...etc
我看到的每个示例都使用 setValidating(true),该方法现已弃用,因此会引发异常。
这是我到目前为止的 Java 代码,它似乎只进行 XML 验证,而不进行模式验证:
try {
JAXBContext jc = new JAXBContext() {
private final JAXBContext jaxbContext = JAXBContext.newInstance("blah");
@Override
public Unmarshaller createUnmarshaller() throws JAXBException {
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
ValidationEventCollector vec = new ValidationEventCollector() {
@Override
public boolean handleEvent(ValidationEvent event) throws RuntimeException {
ValidationEventLocator vel = event.getLocator();
if (event.getSeverity() == event.ERROR || event.getSeverity() == event.FATAL_ERROR) {
String error = "XML Validation Exception: " + event.getMessage() + " at row: " + vel.getLineNumber() + " column: " + vel.getColumnNumber();
System.out.println(error);
}
m_unmarshallingOk = false;
return false;
}
};
unmarshaller.setEventHandler(vec);
return unmarshaller;
}
@Override
public Marshaller createMarshaller() throws JAXBException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
@SuppressWarnings("deprecation")
public Validator createValidator() throws JAXBException {
throw new UnsupportedOperationException("Not supported yet.");
}
};
Unmarshaller unmarshaller = jc.createUnmarshaller();
m_ddsSettings = (com.ultra.DDSSettings)unmarshaller.unmarshal(new File(xmlfileName));
} catch (UnmarshalException ex) {
Logger.getLogger(UniversalDomainParticipant.class.getName()).log(
Level.SEVERE,
null, ex);
} catch (JAXBException ex) {
Logger.getLogger(UniversalDomainParticipant.class.getName()).log(
Level.SEVERE,
null, ex);
}
那么进行此验证的正确方法是什么?我期望 JAXB 生成的类上有一个 validate() 方法,但我想这对于 Java 来说太简单了。
I've been looking for solutions to this problem for far too long considering how easy it sounds so I've come for some help.
I have an XML Schema which I have used with xjc to create my JAXB binding. This works fine when the XML is well formed. Unfortunately it also doesn't complain when the XML is not well formed. I cannot figure out how to do proper full validation against the schema when I try to unmarshall an XML file.
I have managed to use a ValidationEventCollector to handle events, which works for XML parsing errors such as mismatched tags but doesn't raise any events when there is a tag that is required but is completely absent.
From what I have seen validation can be done againsta schema, but you must know the path to the schema in order to pass it into the setSchema() method. The problem I have is that the path to the schema is stored in the XML header and I can't knwo at run time where the schema is going to be. Which is why it's stored in the XML file:
<?xml version="1.0" encoding="utf-8"?>
<DDSSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="/a/big/long/path/to/a/schema/file/DDSSettings.xsd">
<Field1>1</Field1>
<Field2>-1</Field2>
...etc
Every example I see uses setValidating(true), which is now deprecated, so throws an exception.
This is the Java code I have so far, which seems to only do XML validation, not schema validation:
try {
JAXBContext jc = new JAXBContext() {
private final JAXBContext jaxbContext = JAXBContext.newInstance("blah");
@Override
public Unmarshaller createUnmarshaller() throws JAXBException {
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
ValidationEventCollector vec = new ValidationEventCollector() {
@Override
public boolean handleEvent(ValidationEvent event) throws RuntimeException {
ValidationEventLocator vel = event.getLocator();
if (event.getSeverity() == event.ERROR || event.getSeverity() == event.FATAL_ERROR) {
String error = "XML Validation Exception: " + event.getMessage() + " at row: " + vel.getLineNumber() + " column: " + vel.getColumnNumber();
System.out.println(error);
}
m_unmarshallingOk = false;
return false;
}
};
unmarshaller.setEventHandler(vec);
return unmarshaller;
}
@Override
public Marshaller createMarshaller() throws JAXBException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
@SuppressWarnings("deprecation")
public Validator createValidator() throws JAXBException {
throw new UnsupportedOperationException("Not supported yet.");
}
};
Unmarshaller unmarshaller = jc.createUnmarshaller();
m_ddsSettings = (com.ultra.DDSSettings)unmarshaller.unmarshal(new File(xmlfileName));
} catch (UnmarshalException ex) {
Logger.getLogger(UniversalDomainParticipant.class.getName()).log(
Level.SEVERE,
null, ex);
} catch (JAXBException ex) {
Logger.getLogger(UniversalDomainParticipant.class.getName()).log(
Level.SEVERE,
null, ex);
}
So what is the proper way to do this validation? I was expecting there to be a validate() method on the JAXB generated classes, but I guess that would be too simple for Java.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
好的,我找到了解决方案。使用架构工厂创建架构,但不指定架构文件,使其可以与 XML 文件中指定的 noNamespaceSchemaLocation 配合使用。
因此,上面的代码添加了以下内容:
真可惜,花了 24 小时的大部分时间才找到答案!
SchemaFactory.newSchema()
说:OK, I've found the solution. Using the schema factory to create a schema, but without specifying a schema file makes it work with the noNamespaceSchemaLocation specified in the XML file.
So the code from above has had this added:
Shame that took the best part of 24 hours to find the answer to!
The javadoc for
SchemaFactory.newSchema()
says:据我所知,您只需使用 Marshaller.setSchema() 到由 SchemaFactory 来自您的
DDSSettings.xsd
。这将打开验证。As far as I know, you just have to set the schema with Marshaller.setSchema() to a schema created by the SchemaFactory from your
DDSSettings.xsd
. This will turn validation on.