Проверка по схеме с помощью JAXB
Я слишком долго искал решения этой проблемы, учитывая, насколько легко это звучит, поэтому я пришел за помощью.
У меня есть XML-схема, которую я использовал с xjc для создания своей привязки 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>
...так далее
Каждый пример, который я вижу, использует 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.
2 ответа
ОК, я нашел решение. Использование фабрики схем для создания схемы, но без указания файла схемы, заставляет его работать с 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 этот метод создает объект схемы, который выполняет проверку с использованием подсказок местоположения, указанных в документах.
Возвращенный объект схемы предполагает, что если документы ссылаются на один и тот же URL в подсказках расположения схемы, они всегда будут преобразовываться в один и тот же документ схемы. Это утверждение позволяет реализациям повторно использовать проанализированные результаты документов схемы, чтобы несколько проверок одной и той же схемы выполнялись быстрее.
Насколько я знаю, вам просто нужно установить схему с Marshaller.setSchema() на схему, созданную SchemaFactory из вашего DDSSettings.xsd
, Это включит проверку.