синтаксический анализ недействительного xml с использованием jaxb - может ли синтаксический анализатор быть более снисходительным?

Я уже некоторое время использую 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-файла с ошибками.< br/> Итак, если 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 объект с таким объемом данных, который можно было проанализировать до возникновения ошибки.


person samz    schedule 16.07.2012    source источник
comment
Простой вопрос о проблемах: вы заметили, что одна и та же ошибка появлялась повторно? Например, тег ‹A› во многих местах не закрыт?   -  person xwang    schedule 01.07.2016


Ответы (2)


Этот ответ действительно помог мне:

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);
        }
    }
}
person Kevin    schedule 31.03.2015

Философия XML заключается в том, что создатели XML несут ответственность за создание правильно сформированного XML, а получатели не несут ответственности за исправление поврежденного XML по прибытии. Синтаксические анализаторы XML должны отклонять неправильно сформированный XML. Существуют и другие «аккуратные» инструменты, которые могут преобразовать плохой XML в хороший XML, но в зависимости от характера ошибок во входных данных невозможно предсказать, насколько хорошо они будут работать. Если вы хотите получить преимущества от использования XML для обмена данными, он должен быть правильно сформирован. В противном случае вы могли бы также использовать свой собственный формат.

person Michael Kay    schedule 16.07.2012
comment
К сожалению, в реальной жизни не все придерживаются этой философии. В моем сценарии отправляющая сторона пытается отправить правильный xml (а не какой-то специальный формат), но безуспешно по многим причинам (в основном из-за их плохого кода). Я должен как-то справиться с этим. Я пытаюсь максимально использовать встроенные инструменты Java высокого уровня (jaxb), не создавая собственный парсер (переходя на низкий уровень). Любые полезные комментарии/код будут приветствоваться. - person samz; 19.07.2012
comment
Да, реальная жизнь беспорядочна. К счастью, я могу сказать вам, что такое правильное техническое решение, и оставить вас решать проблему, связанную с тем, что у вас недостаточно контроля над всей системой для реализации правильного технического решения. - person Michael Kay; 20.07.2012
comment
Меня интересует техническое решение. Я уже использую JAXB, но довольно простым способом. Я не знаю, как реализовать это решение, и я не нашел никакой полезной информации в Интернете. Вот почему я оказался здесь... - person samz; 24.07.2012
comment
@MichaelKay Как вы относитесь к идее исправления искаженных файлов xml? Каковы наиболее распространенные ошибки в этих искаженных файлах xml? Не могли бы вы поделиться некоторыми мыслями/инсайтами? - person xwang; 01.07.2016
comment
Я уже поделился своими мыслями и наблюдениями. Не миритесь с данными, которые не являются XML. Если бы кто-то дал вам ноутбук, а диск был сломан, вы бы отправили его обратно, а не пытались его починить. Не миритесь с дрянным качеством. - person Michael Kay; 02.07.2016