Читайте из Stax XMLStreamReader, чтобы разобрать частичное - PullRequest
0 голосов
/ 27 апреля 2018

Я работаю с API-курсором Stax для извлечения данных из больших XML-файлов. Тока я иду к началу специального тега и отменяю тег с помощью JAXB. Это хорошо работает на правильно сформированных XML-файлах. Но не так давно у меня был документ, в котором один из сотен тысяч тегов не был закрыт. JAXB работал с XMLStreamReader до конца документа и завершился ошибкой. Есть ли способ прочитать из начального тега в закрывающий тег и удалить его отдельно? Таким образом, я бы потерял два тега с исключением, а не остальную часть документа. Единственным способом, который я нашел, было использование обычного BufferedReader вместо XMLStreamReader и проверка содержимого строки. Но это решение кажется мне безобразным.

1 Ответ

0 голосов
/ 27 апреля 2018

У меня был достаточный успех при использовании Джексона для десериализации фрагментов XML. Когда отдельные операции чтения не удаются, процесс может быть восстановлен путем перемещения курсора к следующему фрагменту:

import com.fasterxml.jackson.dataformat.xml.XmlMapper;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.io.StringReader;

public class XmlFragmentReader {
    public static void main(String[] args) throws XMLStreamException {
        String xml =
            "<list>\n" +
            "<object><name>a</name></object>\n" +
            "<object><name>b</name>\n" + // Missing closing tag
            "<object><name>c</name></object>\n" +
            "<object><name>d</name></object>\n" +
            "<object><name>e</name></object>\n" +
            "</list>";

        XMLStreamReader reader = XMLInputFactory
            .newInstance()
            .createXMLStreamReader(new StringReader(xml));

        XmlMapper mapper = new XmlMapper();
        while (next(reader, "object")) {
            try {
                Obj obj = mapper.readValue(reader, Obj.class);
                System.out.println("Read: " + obj.getName());
            } catch (Exception e) {
                System.err.println("Read Failed: " + e);
            }
        }
    }

    // Advance cursor to the opening tag <name>
    private static boolean next(XMLStreamReader reader, String name) throws XMLStreamException {
        while (true) {
            if (reader.getEventType() == XMLStreamConstants.START_ELEMENT && reader.getLocalName().equals(name)) {
                return true;
            } else if (!reader.hasNext()) {
                return false;
            }
            reader.next();
        }
    }

    // Test object
    @XmlRootElement(name = "object")
    public static class Obj {
        private String name;

        @XmlElement
        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
}

Выход:

Read a
Read d
Read e
...