Разбор очень больших XML-документов (и немного больше) в java

(Все нижеследующее должно быть написано на Java)

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

Сначала поток будет расшифрован согласно вышеупомянутому алгоритму.

Во-вторых, класс расширения (написанный третьей стороной для API, который я предоставляю) будет читать некоторую часть файла. Объем чтения непредсказуем - в частности, не гарантируется, что он будет в заголовке файла, но может произойти в любой точке XML.

Наконец, другой класс расширения (такая же сделка) разделит входной XML на 1..n подмножеств документов. Вполне возможно, что они будут частично перекрывать часть документа, обрабатываемую второй операцией, то есть: я считаю, что мне нужно будет перемотать любой механизм, который я использую для работы с этим объектом.

Вот мой вопрос:

Есть ли способ сделать это, никогда не считывая данные в память целиком? Очевидно, я могу реализовать дешифрование как фильтр входного потока, но я не уверен, можно ли анализировать XML так, как я описываю; пройдя по документу, необходимому для сбора информации на втором этапе, а затем перемотав документ и перемотав его снова, чтобы разделить его на задания, в идеале освободив все части документа, которые больше не используются после они прошли.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
19
0
24 471
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Вы можете использовать BufferedInputStream с очень большим размером буфера и использовать mark() до того, как сработает класс расширения, а затем reset().

Однако, если части, необходимые классу расширения, находятся очень далеко в файле, это может стать чрезвычайно интенсивным по памяти ».

Более общим решением было бы написать свой собственный BufferedInputStream-аналог, который буферизует диск, если данные, которые должны быть буферизованы, превышают некоторый заранее установленный порог.

Вас может заинтересовать XOM:

XOM is fairly unique in that it is a dual streaming/tree-based API. Individual nodes in the tree can be processed while the document is still being built. The enables XOM programs to operate almost as fast as the underlying parser can supply data. You don't need to wait for the document to be completely parsed before you can start working with it.

XOM is very memory efficient. If you read an entire document into memory, XOM uses as little memory as possible. More importantly, XOM allows you to filter documents as they're built so you don't have to build the parts of the tree you aren't interested in. For instance, you can skip building text nodes that only represent boundary white space, if such white space is not significant in your application. You can even process a document piece by piece and throw away each piece when you're done with it. XOM has been used to process documents that are gigabytes in size.

Это выглядит интересным и потенциально полезным подходом, но нигде в документации он не предлагает способ управления синтаксическим анализом документа описанным вами способом. Я считаю, что это может, но возможность не задокументирована таким образом, чтобы ее можно было обнаружить.

Chris R 10.12.2008 17:05

Похоже, это работа для StAX (JSR 173). StAX - это анализатор вывода, что означает, что он работает более или менее как синтаксический анализатор на основе событий, такой как SAX, но у вас больше контроля над тем, когда прекратить чтение, какие элементы вытащить, ...

Удобство использования этого решения будет во многом зависеть от того, что на самом деле делают ваши классы расширения, есть ли у вас контроль над их реализацией и т. д.

Суть в том, что если документ очень большой, вы, вероятно, захотите использовать анализатор на основе событий, а не на основе дерева, поэтому вы не будете использовать много памяти.

Реализации StAX можно найти у SUN (SJSXP), Codehaus или у нескольких других поставщиков.

Это выглядит многообещающе, если я могу эффективно к нему подключиться. Похоже, мне придется предоставить StAX клиентам моего API, что далеко не идеально, но, по крайней мере, похоже, что возможности есть. Можете ли вы изменить свой пост, указав рекомендуемую реализацию вместо списка?

Chris R 10.12.2008 18:41

Я знаю, что это старый ответ / комментарий, но есть некоторые библиотеки, которые могут добавить немного большего удобства поверх stax (и изолировать некоторые детали более низкого уровня), например StaxMate [staxmate.codehaus.org/Tutorial]. Это по-прежнему позволяет выполнять инкрементный синтаксический анализ / запись, но сокращает объем написанного кода.

StaxMan 06.05.2009 10:07
Ответ принят как подходящий

Stax - правильный путь. Я бы порекомендовал посмотреть Woodstox

Я бы написал собственную реализацию InputStream, которая расшифровывает байты в файле, а затем использует SAX для анализа результирующего XML по мере его выхода из потока.

SAXParserFactory.newInstance().newSAXParser().parse(
  new DecryptingInputStream(), 
  new MyHandler()
);

Посмотрите библиотеку XOM. Пример, который вы ищете, - это StreamingExampleExtractor.java в каталоге примеров исходного дистрибутива. Здесь показан метод выполнения потокового анализа большого XML-документа, построенный только на определенных узлах, их обработка и отбрасывание. Он очень похож на подход sax, но имеет гораздо больше встроенных возможностей синтаксического анализа, поэтому потоковый синтаксический анализ может быть выполнен довольно легко.

Если вы хотите работать на более высоком уровне, посмотрите NUX. Это обеспечивает высокоуровневый потоковый API xpath, который считывает в память только тот объем данных, который необходим для оценки xpath.

Другие вопросы по теме