Я уже некоторое время использую JAXB для анализа xml, который выглядит примерно так:
<report> <-- corresponds to a "wrapper" object that holds
some properties and two lists - a list of A's and list of B's
<some tags with> general <info/>
...
<A> <-- corresponds to an "A" object with some properties
<some tags with> info related to the <A> tag <bla/>
...
<A/>
<B> <-- corresponds to an "B" object with some properties
<some tags with> info related to the <B> tag <bla/>
...
</B>
</report>
Сторона, ответственная за сортировку xml, ужасна, но я не могу ее контролировать.
Она часто отправляет недопустимые символы xml и/или искаженный xml.
Я поговорил с ответственной стороной и исправил множество ошибок, но некоторые они просто не могут исправить.
Я хочу, чтобы мой синтаксический анализатор был максимально снисходителен к этим ошибкам, а когда это невозможно, чтобы получить как можно больше информации из XML-файла с ошибками. Итак, если xml содержит 100 A и у одного есть проблема, я все равно хотел бы сохранить остальные 99.
Вот мои самые распространенные проблемы:
1. Some info tag inner value contains invalid chars
<bla> invalid chars here, either control chars or just &>< </bla>
2. The root entity is missing a closing tag
<report> ..... stuff here .... NO </report> at the end!
3. An inner entity (A/B) is missing it's closing tag, or it's somehow malformed.
<A> ...stuff here... <somethingMalformed_blabla_A/>
OR
<A> ... Something malformed here...</A>
Я надеялся, что объяснил себя хорошо.
Я действительно хочу получить как можно больше информации из этих XML-файлов, даже если у них есть проблемы.
Думаю, мне нужно использовать некоторую стратегию, которая использует stax/sax вместе с JAXB, но я не знаю, как это сделать.
Если из 100 баллов A один A имеет проблему с xml, я не против выкинуть только этот A.
Хотя было бы намного лучше, если бы я мог получить A объект с таким объемом данных, который можно было проанализировать до возникновения ошибки.
Ответ 1 · рейтинг 2 · Kevin
Этот ответ действительно помог мне:
JAXB - неупорядочивание XML-исключения
В моем случае я анализирую результаты инструмента Sysinternals Autoruns с переключателем XML (-x). Либо из-за того, что результаты записывались в общую папку, либо из-за какой-то ошибки в более новой версии XML был бы искажен ближе к концу. Поскольку этот захват Autoruns имеет решающее значение для расследования вредоносных программ, мне очень нужны были данные. Кроме того, по размеру файла я мог сказать, что результаты были почти полными.
Решение в связанном вопросе работает очень хорошо, когда у вас есть документ со многими подэлементами, как это было предложено OP. В частности, XML-вывод Autoruns очень прост и состоит из множества "элементов", каждый из которых состоит из множества простых элементов с текстом (т. е. строковых свойств, сгенерированных XJC). Так что, если в конце пропущено несколько элементов, ничего страшного... если, конечно, это не связано с вредоносным ПО. :)
Вот мой код:
public class Loader {
private List<Exception> exceptions = new ArrayList<>();
public synchronized List<Exception> getExceptions() {
return new ArrayList<>(exceptions);
}
protected void setExceptions(List<Exception> exceptions) {
this.exceptions = exceptions;
}
public synchronized Autoruns load(File file, boolean attemptRecovery)
throws LoaderException {
Unmarshaller unmarshaller;
try {
JAXBContext context = newInstance(Autoruns.class);
unmarshaller = context.createUnmarshaller();
} catch (JAXBException ex) {
throw new LoaderException("Could not create unmarshaller.", ex);
}
try {
return (Autoruns) unmarshaller.unmarshal(file);
} catch (JAXBException ex) {
if (!attemptRecovery) {
throw new LoaderException(ex.getMessage(), ex);
}
}
exceptions.clear();
Autoruns autoruns = new Autoruns();
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
try {
XMLEventReader eventReader =
inputFactory.createXMLEventReader(new FileInputStream(file));
while (eventReader.hasNext()) {
XMLEvent event = eventReader.peek();
if (event.isStartElement()) {
StartElement start = event.asStartElement();
if (start.getName().getLocalPart().equals("item")) {
// note the try should allow processing of elements
// after this item in the event it is malformed
try {
JAXBElement<Autoruns.Item> jax_b =
unmarshaller.unmarshal(eventReader,
Autoruns.Item.class);
autoruns.getItem().add(jax_b.getValue());
} catch (JAXBException ex) {
exceptions.add(ex);
}
}
}
eventReader.next();
}
} catch (XMLStreamException | FileNotFoundException ex) {
exceptions.add(ex);
}
return autoruns;
}
public static Autoruns load(Path path) throws JAXBException {
return load(path.toFile());
}
public static Autoruns load(File file) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(Autoruns.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
return (Autoruns) unmarshaller.unmarshal(file);
}
public static class LoaderException extends Exception {
public LoaderException(String message) {
super(message);
}
public LoaderException(String message, Throwable cause) {
super(message, cause);
}
}
}
Ответ 2 · рейтинг 2 · Michael Kay
Философия XML заключается в том, что создатели XML несут ответственность за создание правильно сформированного XML, а получатели не несут ответственности за исправление поврежденного XML по прибытии. Синтаксические анализаторы XML должны отклонять неправильно сформированный XML. Существуют и другие "аккуратные" инструменты, которые могут преобразовать плохой XML в хороший XML, но в зависимости от характера ошибок во входных данных невозможно предсказать, насколько хорошо они будут работать. Если вы хотите получить преимущества от использования XML для обмена данными, он должен быть правильно сформирован. В противном случае вы могли бы также использовать свой собственный формат.