使用JAXB验证架构 [英] Validating against a Schema with JAXB

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

问题描述

我一直在寻找这个问题的解决方案,考虑到它听起来有多容易,所以我来寻求帮助。

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.

我有一个XML我用xjc创建我的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,此方法创建一个
Schema对象,该对象使用
文档中指定的位置提示执行验证

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

返回的Schema对象假设
,如果文档在架构位置提示中引用相同的
URL,则
将始终解析为相同的架构
文档。这个asusmption允许
实现重用解析后的
架构文档结果,这样
对同一
架构的多次验证运行得更快。

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验证架构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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