Существует ли парсированный / неблокирующий парсер XML для Java? - PullRequest
17 голосов
/ 21 июня 2009

Я ищу синтаксический анализатор XML, который вместо синтаксического анализа InputStream или InputSource будет позволять вставлять блоки текста в синтаксический анализатор. Например. Я хотел бы иметь что-то вроде следующего:

public class DataReceiver {
    private SAXParser parser = //...
    private DefaultHandler handler = //...

    /**
     * Called each time some data is received.
     */
    public void onDataReceived(byte[] data) {
        parser.push(data, handler);
    }
}

Причина в том, что мне бы хотелось, чтобы что-то было хорошо с сетевыми библиотеками NIO, а не возвращалось к потоку для каждой модели соединения, необходимой для поддержки блокирующего InputStream.

Ответы [ 7 ]

7 голосов
/ 31 августа 2010

Удивительно, но никто не упомянул один синтаксический анализатор Java XML, который реализует неблокирующий ("асинхронный") анализ: Aalto . Частично причиной может быть отсутствие документации (и ее низкий уровень активности). Aalto реализует базовый API Stax, но также и незначительные расширения, позволяющие толкать ввод (эта часть не была завершена; функциональность существует, но API не завершена). Для получения дополнительной информации вы можете ознакомиться с соответствующей дискуссионной группой .

4 голосов
/ 22 июня 2009

Редактировать: теперь я вижу. Вы получаете XML в виде кусков и хотите передать его в правильный анализатор XML. Итак, вам нужен объект, который является очередью на одном конце и InputStream на другом конце?

Можно объединить полученные байтовые массивы в ByteArrayOutputStream, преобразовать его в ByteArrayInputStream и передать его в SAXParser.

Или вы можете проверить пару PipedInputStream / PipedOutputStream. В этом случае вам нужно будет выполнить синтаксический анализ в другом потоке, так как анализатор SAX использует текущий поток для отправки событий, блокируя вашу receive ().

Редактировать : На основании комментариев я предлагаю выбрать маршрут агрегации. Вы собираете куски в ByteArrayOutputStream. Чтобы узнать, получили ли вы все фрагменты для вашего XML, проверьте, содержит ли текущий фрагмент или содержимое ByteArrayOutputStream ваш конечный тег корневого узла XML. Затем вы можете просто передать данные в SAXParser, который теперь может без проблем работать в текущем потоке. Чтобы избежать ненужного пересоздания массива, вы можете реализовать свою собственную несинхронизированную оболочку простого байтового массива или искать такую ​​реализацию.

3 голосов
/ 26 июня 2009

Это сообщение (апрель 2009 г.) из списка рассылки Xerces J-Users, в котором оригинальный постер имеет точно такую ​​же проблему. Дается потенциально один очень хороший ответ Джеффа, но нет ответа на первоначальный ответ автора:

http://www.nabble.com/parsing-an-xml-document-chunk-by-chunk-td22945319.html

Он потенциально достаточно новый, чтобы врезаться в список или, по крайней мере, помочь с поиском.

Редактировать

Нашел еще одну полезную ссылку, упомянув библиотеку под названием Woodstox и описав состояние анализаторов Stream по сравнению с NIO и некоторые возможные подходы к эмуляции потока:

http://markmail.org/message/ogqqcj7dt3lwkbov

1 голос
/ 09 июня 2013

NioSax работает с байтовыми буферами

http://blog.retep.org/2010/06/25/niosax-sax-style-xml-parser-for-java-nio/

Исходный код последней версии, которую я смог найти (10.6 из 2010), находится в Репозиторий Sonatype Maven:

https://oss.sonatype.org/content/repositories/releases/uk/org/retep/

1 голос
/ 21 июня 2012

Добавление другого ответа, поскольку этот вопрос остается высоким для релевантных поисков в Google - aalto-xml 0.9.7 (март 2011 г.) имеет асинхронное вставление XML. Это позволяет передавать фрагменты документа произвольного размера для продолжения анализа и нового типа события StaX EVENT_INCOMPLETE, указывающего на то, что входной буфер исчерпан, а документ остается неполным.

Это Пример Тату Салорана (автора):

     byte[] msg = "<html>Very <b>simple</b> input document!</html>".getBytes();
      AsyncXMLStreamReader asyncReader = new InputFactoryImpl().createAsyncXMLStreamReader();
      final AsyncInputFeeder feeder = asyncReader.getInputFeeder();
      int inputPtr = 0; // as we feed byte at a time
      int type = 0;

      do {
        // May need to feed multiple "segments"
        while ((type = asyncReader.next()) == AsyncXMLStreamReader.EVENT_INCOMPLETE) {
          feeder.feedInput(msg, inputPtr++, 1);
          if (inputPtr >= msg.length) { // to indicate end-of-content (important for error handling)
            feeder.endOfInput();
          }
        }
        // and once we have full event, we just dump out event type (for now)
        System.out.println("Got event of type: "+type);
        // could also just copy event as is, using Stax, or do any other normal non-blocking handling:
        // xmlStreamWriter.copyEventFromReader(asyncReader, false);
      } while (type != AsyncXMLStreamReader.END_DOCUMENT);
0 голосов
/ 26 июня 2009

Извините, мне не удалось решить эту проблему. Я не мог найти парсер как тот, который мне нужен. Но я думаю написать один сам. Очень просто: просто как исследование финансов, но достаточно, чтобы решить мою проблему и, надеюсь, вашу. К сожалению, я был очень делов, и следующие две недели я буду отсутствовать, но, возможно, в июле я начну работать над этим. Я дам вам знать, как только у меня что-нибудь получится.

т

...