Bezdepbonusu7Программирование: статьи и ответы

Вопрос

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

Автор вопроса: samzОтветов: 2

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

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

xmlparsingjaxb

Ответы

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

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы