13

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

我有一个与 xjc 一起使用的 XML Schema 来创建我的 JAXB 绑定。当 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>

...ETC

我看到的每个示例都使用 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

好的,我找到了解决方案。使用架构工厂创建架构,但不指定架构文件,使其与 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 小时的大部分时间才找到答案的耻辱!

javadocSchemaFactory.newSchema()说:

对于 XML Schema,此方法创建一个 Schema 对象,该对象使用文档中指定的位置提示执行验证。

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

于 2010-03-22T12:27:56.357 回答
1

据我所知,您只需使用Marshaller.setSchema()将架构设置为由SchemaFactory从您的DDSSettings.xsd. 这将打开验证。

于 2010-03-22T11:54:03.460 回答