我需要在编组到XML文件之前验证我的JAXB对象。在JAXB 2.0之前,可以使用javax.xml.bind.Validator。但是这已被弃用,所以我试图弄清楚这样做的正确方法。我熟悉马歇尔时间的验证,但就我而言,我只想知道它是否有效。我想我可以对一个临时文件或内存进行编组并抛弃它,但想知道是否有更优雅的解决方案。
答案 0 :(得分:72)
首先,javax.xml.bind.Validator
已被弃用,转而使用javax.xml.validation.Schema
(javadoc)。我们的想法是通过javax.xml.validation.SchemaFactory
(javadoc)解析您的模式,并将其注入marshaller / unmarshaller。
关于没有编组的验证问题,这里的问题是JAXB实际上将验证委托给Xerces(或者你正在使用的SAX处理器),并且Xerces将你的文档验证为SAX事件流。因此,为了验证,您需要执行一些类型的编组。
影响最小的实现是使用SAX处理器的“/ dev / null”实现。编组为null OutputStream仍然会涉及XML生成,这是浪费。所以我建议:
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema(locationOfMySchema);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setSchema(schema);
marshaller.marshal(objectToMarshal, new DefaultHandler());
DefaultHandler
将丢弃所有事件,如果针对架构的验证失败,marshal()
操作将抛出JAXBException。
答案 1 :(得分:11)
您可以使用javax.xml.bind.util.JAXBSource
(javadoc)和javax.xml.validation.Validator
(javadoc),投入org.xml.sax.ErrorHandler
的实施(javadoc并执行以下操作:
import java.io.File;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.util.JAXBSource;
import javax.xml.validation.*;
public class Demo {
public static void main(String[] args) throws Exception {
Customer customer = new Customer();
customer.setName("Jane Doe");
customer.getPhoneNumbers().add(new PhoneNumber());
customer.getPhoneNumbers().add(new PhoneNumber());
customer.getPhoneNumbers().add(new PhoneNumber());
JAXBContext jc = JAXBContext.newInstance(Customer.class);
JAXBSource source = new JAXBSource(jc, customer);
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = sf.newSchema(new File("customer.xsd"));
Validator validator = schema.newValidator();
validator.setErrorHandler(new MyErrorHandler());
validator.validate(source);
}
}
有关详细信息,请参阅我的博客
答案 2 :(得分:4)
我们是怎么做到的。我必须找到一种方法来验证xml文件与xml版本相对应的xsd,因为我们有许多应用程序使用不同版本的xml内容。
我在网上找不到任何好的例子,最后完成了这个。希望这会有所帮助。
ValidationEventCollector vec = new ValidationEventCollector();
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
URL xsdURL = getClass().getResource("/xsd/" + xsd);
Schema schema = sf.newSchema(xsdURL);
//You should change your jaxbContext here for your stuff....
Unmarshaller um = (getJAXBContext(NotificationReponseEnum.NOTIFICATION, notificationWrapper.getEnteteNotification().getTypeNotification()))
.createUnmarshaller();
um.setSchema(schema);
try {
StringReader reader = new StringReader(xml);
um.setEventHandler(vec);
um.unmarshal(reader);
} catch (javax.xml.bind.UnmarshalException ex) {
if (vec != null && vec.hasEvents()) {
erreurs = new ArrayList < MessageErreur > ();
for (ValidationEvent ve: vec.getEvents()) {
MessageErreur erreur = new MessageErreur();
String msg = ve.getMessage();
ValidationEventLocator vel = ve.getLocator();
int numLigne = vel.getLineNumber();
int numColonne = vel.getColumnNumber();
erreur.setMessage(msg);
msgErreur.setCode(ve.getSeverity())
erreur.setException(ve.getLinkedException());
erreur.setPosition(numLigne, numColonne);
erreurs.add(erreur);
logger.debug("Erreur de validation xml" + "erreur : " + numLigne + "." + numColonne + ": " + msg);
}
}
}