Подтвердить что ты не робот

Проверка схемы с помощью JAXB

Я искал решения этой проблемы слишком долго, учитывая, насколько легко это звучит, поэтому я пришла за помощью.

У меня есть XML-схема, которую я использовал с xjc для создания привязки JAXB. Это отлично работает, когда XML хорошо сформирован. К сожалению, он также не жалуется, когда XML не очень хорошо сформирован. Я не могу понять, как сделать правильную полную проверку против схемы, когда я пытаюсь разобрать XML файл.

Мне удалось использовать ValidationEventCollector для обработки событий, который работает для XML-анализа синтаксических ошибок, таких как несогласованные теги, но не вызывает никаких событий, когда есть тег, который требуется, но полностью отсутствует.

Из того, что я видел, проверка может быть проведена против схемы, но вы должны знать путь к схеме, чтобы передать ее в метод setSchema(). Проблема в том, что путь к схеме хранится в заголовке XML, и я не могу knwo во время выполнения, где будет схема. Вот почему он хранится в 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);
}

Итак, каков правильный способ сделать эту проверку? Я ожидал, что будет существовать метод validate() на сгенерированных классах JAXB, но я думаю, это было бы слишком просто для Java.

4b9b3361

Ответ 1

Хорошо, я нашел решение. Используя схему factory для создания схемы, но без указания файла схемы, она работает с noNamespaceSchemaLocation, указанным в XML файле.

Таким образом, код сверху добавил:

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 в подсказках местоположения схемы, они всегда будет решать одну и ту же схему документ. Это предположение позволяет реализации для повторного использования проанализированных результатов схемных документов, чтобы множественные проверки против того же схема будет работать быстрее.

Ответ 2

Насколько мне известно, вам просто нужно установить схему Marshaller.setSchema() в схему, созданную SchemaFactory из вашего DDSSettings.xsd. Это вернет подтверждение.