Как проверить схему в JAXB 2.0 без маршалинга?

Мне нужно проверить мои объекты JAXB перед отправкой в ​​файл XML. До JAXB 2.0 можно было использовать javax.xml.bind.Validator. Но это устарело, поэтому я пытаюсь найти правильный способ сделать это. Я знаком с валидацией во время маршала, но в моем случае я просто хочу знать, действительно ли она действительна. Я полагаю, я мог бы собрать временный файл или память и выбросить его, но подумал, есть ли более элегантное решение.

13.10.2009 13:57:20
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, если проверка по схеме не удалась.

77
8.09.2017 09:37:07
Из какого пакета вы берете DefaultHandler? Это из org.xml.sax.helpers?
Stefan Höltker 29.05.2019 09:04:04
tom_mai78101 24.03.2020 12:58:13

Вот как мы это сделали. Мне нужно было найти способ проверить файл 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);
        }
    }
}
4
9.08.2017 03:38:22

Вы можете использовать javax.xml.bind.util.JAXBSource( javadoc ) и a 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);
    }

}

Для получения дополнительной информации см. Мой блог

12
8.09.2017 10:57:21
Одна проблема с этим подходом: вы не получаете номер строки / номер столбца информации об ошибках проверки с помощью этого метода, поэтому трудно отследить проблемы.
Erwin Bolwidt 2.06.2015 07:20:38
Применим ли этот подход для Unmarchalling. Я не могу создать объект JAXBSource.
Xelian 17.06.2016 11:15:21