如何在没有编组的情况下验证JAXB 2.0中的模式?

Joe*_*oel 48 java jaxb

我需要在编组到XML文件之前验证我的JAXB对象.在JAXB 2.0之前,可以使用javax.xml.bind.Validator.但是这已被弃用,所以我试图弄清楚这样做的正确方法.我熟悉马歇尔时间的验证,但就我而言,我只想知道它是否有效.我想我可以对一个临时文件或内存进行编组并抛弃它,但想知道是否有更优雅的解决方案.

ska*_*man 73

首先,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());
Run Code Online (Sandbox Code Playgroud)

DefaultHandler将丢弃所有事件,marshal()如果针对架构的验证失败,操作将抛出JAXBException.


bdo*_*han 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);
    }

}
Run Code Online (Sandbox Code Playgroud)

有关详细信息,请参阅我的博客

  • 此方法存在一个问题:使用此方法无法获得有关验证错误的行号/列号信息,因此很难跟踪问题. (2认同)

Pat*_*t B 5

我们就是这样做的。我必须找到一种方法来验证 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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)