13

私はこの問題の解決策をずっと探していましたが、それがいかに簡単に聞こえるかを考えて、助けを求めてきました。

JAXBバインディングを作成するためにxjcで使用したXMLスキーマがあります。これは、XMLが適切に形成されている場合に正常に機能します。残念ながら、XMLが適切に形成されていない場合も文句はありません。XMLファイルをアンマーシャリングしようとすると、スキーマに対して適切な完全検証を行う方法がわかりません。

ValidationEventCollectorを使用してイベントを処理することができました。これは、タグの不一致などのXML解析エラーに対して機能しますが、必要なタグが完全に存在しない場合はイベントを発生させません。

私が見たところ、スキーマに対して検証を行うことができますが、それをsetSchema()メソッドに渡すには、スキーマへのパスを知っている必要があります。私が抱えている問題は、スキーマへのパスがXMLヘッダーに格納されており、実行時にスキーマがどこにあるかを知ることができないことです。これが、XMLファイルに保存される理由です。

<?xml version="1.0" encoding="utf-8"?>
<DDSSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="/a/big/long/path/to/a/schema/file/DDSSettings.xsd">
<Field1>1</Field1>
<Field2>-1</Field2>

...等

私が見るすべての例はsetValidating(true)を使用していますが、これは現在非推奨であるため、例外をスローします。

これは私がこれまでに持っているJavaコードであり、スキーマ検証ではなくXML検証のみを行うようです。

try {
    JAXBContext jc = new JAXBContext() {
        private final JAXBContext jaxbContext = JAXBContext.newInstance("blah");

        @Override
        public Unmarshaller createUnmarshaller() throws JAXBException {
            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
            ValidationEventCollector vec = new ValidationEventCollector() {
                @Override
                public boolean handleEvent(ValidationEvent event) throws RuntimeException {
                    ValidationEventLocator vel = event.getLocator();
                    if (event.getSeverity() == event.ERROR || event.getSeverity() == event.FATAL_ERROR) {
                        String error = "XML Validation Exception:  " + event.getMessage() + " at row: " + vel.getLineNumber() + " column: " + vel.getColumnNumber();
                        System.out.println(error);
                    }
                    m_unmarshallingOk = false;
                    return false;
                }
            };
            unmarshaller.setEventHandler(vec);

            return unmarshaller;
        }

        @Override
        public Marshaller createMarshaller() throws JAXBException {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        @SuppressWarnings("deprecation")
        public Validator createValidator() throws JAXBException {
            throw new UnsupportedOperationException("Not supported yet.");
        }
    };

    Unmarshaller unmarshaller = jc.createUnmarshaller();
    m_ddsSettings = (com.ultra.DDSSettings)unmarshaller.unmarshal(new File(xmlfileName));
} catch (UnmarshalException ex) {
    Logger.getLogger(UniversalDomainParticipant.class.getName()).log(
    Level.SEVERE,
    null, ex);
} catch (JAXBException ex) {
    Logger.getLogger(UniversalDomainParticipant.class.getName()).log(
    Level.SEVERE,
    null, ex);
}

では、この検証を行うための適切な方法は何ですか?JAXBで生成されたクラスにvalidate()メソッドがあることを期待していましたが、Javaには単純すぎると思います。

4

2 に答える 2

15

OK、解決策を見つけました。スキーマファクトリを使用してスキーマを作成しますが、スキーマファイルを指定しないと、XMLファイルで指定されたnoNamespaceSchemaLocationで機能します。

したがって、上記のコードには次のものが追加されています。

SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
Schema schema = factory.newSchema();
Unmarshaller unmarshaller = jc.createUnmarshaller();
unmarshaller.setSchema(schema);
m_ddsSettings = (com.ultra.DDSSettings)unmarshaller.unmarshal(new File(xmlfileName));

答えを見つけるのに24時間の大部分を費やした恥!

のjavadocは次のようにSchemaFactory.newSchema()述べています。

XMLスキーマの場合、このメソッドは、ドキュメントで指定された場所のヒントを使用して検証を実行するスキーマオブジェクトを作成します。

返されるSchemaオブジェクトは、ドキュメントがスキーマロケーションヒントで同じURLを参照している場合、それらは常に同じスキーマドキュメントに解決されると想定しています。この仮定により、実装はスキーマドキュメントの解析結果を再利用できるため、同じスキーマに対する複数の検証がより高速に実行されます。

于 2010-03-22T12:27:56.357 に答える
1

私の知る限り、Marshaller.setSchema()を使用してスキーマを、からSchemaFactoryによって作成されたスキーマに設定する必要がありますDDSSettings.xsd。これにより、検証がオンになります。

于 2010-03-22T11:54:03.460 に答える