Есть ли Push-основанный / неблокирующий синтаксический анализатор XML для Java?


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

7 17

7 ответов:

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

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

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

Edit

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

Http://markmail.org/message/ogqqcj7dt3lwkbov

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

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

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

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

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

Добавим еще один ответ, поскольку этот вопрос остается высоким для релевантных поисков 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);

NioSax работает с ByteBuffers

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/

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

Mt