使用 JAXB 对 Schema 进行验证 [英] Validating against a Schema with JAXB

查看:29
本文介绍了使用 JAXB 对 Schema 进行验证的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑到这听起来很简单,我一直在寻找这个问题的解决方案太久了,所以我来寻求帮助.

I've been looking for solutions to this problem for far too long considering how easy it sounds so I've come for some help.

我有一个与 xjc 一起使用的 XML 模式来创建我的 JAXB 绑定.当 XML 格式正确时,这可以正常工作.不幸的是,当 XML 格式不正确时,它也不会抱怨.当我尝试解组 XML 文件时,我无法弄清楚如何对架构进行正确的完整验证.

I have an XML Schema which I have used with xjc to create my JAXB binding. This works fine when the XML is well formed. Unfortunately it also doesn't complain when the XML is not well formed. I cannot figure out how to do proper full validation against the schema when I try to unmarshall an XML file.

我已经设法使用 ValidationEventCollector 来处理事件,它适用于 XML 解析错误,例如标签不匹配,但在需要标签但完全不存在时不会引发任何事件.

I have managed to use a ValidationEventCollector to handle events, which works for XML parsing errors such as mismatched tags but doesn't raise any events when there is a tag that is required but is completely absent.

据我所知,可以针对模式进行验证,但是您必须知道模式的路径才能将其传递给 setSchema() 方法.我遇到的问题是模式的路径存储在 XML 标头中,我无法在运行时知道模式的位置.这就是它存储在 XML 文件中的原因:

From what I have seen validation can be done againsta schema, but you must know the path to the schema in order to pass it into the setSchema() method. The problem I have is that the path to the schema is stored in the XML header and I can't knwo at run time where the schema is going to be. Which is why it's stored in the XML file:

<?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),现在已弃用,因此会引发异常.

Every example I see uses setValidating(true), which is now deprecated, so throws an exception.

这是我目前的Java代码,似乎只做XML验证,不做模式验证:

This is the Java code I have so far, which seems to only do XML validation, not schema validation:

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 来说太简单了.

So what is the proper way to do this validation? I was expecting there to be a validate() method on the JAXB generated classes, but I guess that would be too simple for Java.

推荐答案

好的,我找到了解决方案.使用架构工厂创建架构,但不指定架构文件,使其与 XML 文件中指定的 noNamespaceSchemaLocation 一起工作.

OK, I've found the solution. Using the schema factory to create a schema, but without specifying a schema file makes it work with the noNamespaceSchemaLocation specified in the XML file.

所以上面的代码已经添加了这个:

So the code from above has had this added:

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 小时才找到答案!

Shame that took the best part of 24 hours to find the answer to!

SchemaFactory.newSchema() 说:

对于 XML Schema,此方法创建一个执行验证的模式对象通过使用指定的位置提示文件.

For XML Schema, this method creates a Schema object that performs validation by using location hints specified in documents.

返回的 Schema 对象假定如果文件提到相同架构位置提示中的 URL,它们将始终解析为相同的架构文档.这个假设允许重用已解析的实现模式文档的结果,以便针对相同的多个验证架构将运行得更快.

The returned Schema object assumes that if documents refer to the same URL in the schema location hints, they will always resolve to the same schema document. This asusmption allows implementations to reuse parsed results of schema documents so that multiple validations against the same schema will run faster.

这篇关于使用 JAXB 对 Schema 进行验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆