Как проверить соответствие схеме в JAXB 2.0 без сортировки?
Мне нужно проверить мои объекты JAXB перед отправкой в файл XML. До JAXB 2.0 можно было использовать javax.xml.bind.Validator. Но это устарело, поэтому я пытаюсь найти правильный способ сделать это. Я знаком с проверкой во время маршала, но в моем случае я просто хочу знать, действительно ли это правильно. Я полагаю, я мог бы собрать временный файл или память и выбросить его, но подумал, есть ли более элегантное решение.
3 ответа
Во-первых, javax.xml.bind.Validator
устарела в пользу javax.xml.validation.Schema
( Javadoc). Идея состоит в том, что вы анализируете свою схему с помощью javax.xml.validation.SchemaFactory
( Javadoc), и введите это в маршаллер / демаршаллер.
Что касается вашего вопроса относительно проверки без маршалинга, проблема здесь в том, что JAXB фактически делегирует проверку Xerces (или любому используемому вами процессору SAX), а Xerces проверяет ваш документ как поток событий SAX. Таким образом, чтобы проверить, вам нужно выполнить какой- то маршаллинг.
Реализация этого с наименьшей эффективностью будет заключаться в использовании "/dev/null" реализации процессора SAX. Маршаллинг для нулевого 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, если проверка по схеме не удалась.
Вы могли бы использовать 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);
}
}
Для получения дополнительной информации см. Мой блог
Вот как мы это сделали. Мне нужно было найти способ проверить xml-файл по сравнению с xsd, соответствующим версии xml, поскольку у нас есть много приложений, использующих разные версии 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);
}
}
}