web-dev-qa-db-ja.com

マーシャリングせずにJAXB 2.0のスキーマに対して検証する方法は?

XMLファイルにマーシャリングする前に、JAXBオブジェクトを検証する必要があります。 JAXB 2.0より前は、javax.xml.bind.Validatorを使用できました。しかし、これは廃止されているため、これを行う適切な方法を見つけようとしています。私はマーシャル時に検証に精通していますが、私の場合は、それが有効かどうかを知りたいだけです。一時ファイルまたはメモリにマーシャリングして破棄することはできますが、よりエレガントな解決策があるかどうか疑問に思います。

48
Joel

まず、_javax.xml.bind.Validator_は非推奨になり、_javax.xml.validation.Schema_( javadoc )が採用されました。アイデアは、_javax.xml.validation.SchemaFactory_( javadoc )を介してスキーマを解析し、それをmarshaller/unmarshallerに挿入することです。

マーシャリングなしの検証に関する質問については、ここでの問題は、JAXBが実際に検証をXerces(または使用しているSAXプロセッサ)に委任し、XercesがドキュメントをSAXイベントのストリームとして検証することです。したがって、検証するには、some種類のマーシャリングを実行する必要があります。

これの最も影響の少ない実装は、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をスローします。

72
skaffman

javax.xml.bind.util.JAXBSourcejavadoc )とjavax.xml.validation.Validatorjavadoc )を使用して、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);
    }

}

詳細については、マイブログを参照してください

11
bdoughan

これが私たちのやり方です。さまざまなバージョンのxmlコンテンツを使用する多くのアプリがあるため、xmlファイルとxmlのバージョンに対応するxsdを検証する方法を見つける必要がありました。

ネット上で良い例が実際に見つからなかったので、最終的にこれで終了しました。これが役立つことを願っています。

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
Pat B