(Все следующее должно быть написано на Java)
Мне нужно создать приложение, которое будет принимать в качестве входных XML-документов, которые могут быть очень большими. Документ зашифрован - не с помощью XMLsec, а с помощью ранее существовавшего алгоритма шифрования моего клиента - будет обрабатываться в три этапа:
Во-первых, поток будет расшифрован в соответствии с вышеупомянутым алгоритмом.
Во-вторых, класс расширения (написанный третьей стороной для API, который я предоставляю) будет считывать некоторую часть файла. Количество прочитанного не предсказуемо - в частности, оно не гарантируется в заголовке файла, но может произойти в любой точке XML.
Наконец, другой класс расширения (та же самая сделка) подразделяет входной XML на документы подмножества 1..n. Возможно, что они в какой-то степени будут перекрывать ту часть документа, которая рассматривается второй операцией, т.е. я считаю, что мне нужно будет перемотать любой механизм, который я использую для работы с этим объектом.
Вот мой вопрос:
Есть ли способ сделать это, не читая весь кусок данных в память за один раз? Очевидно, что я могу реализовать дешифрование в качестве фильтра входного потока, но я не уверен, возможно ли проанализировать XML так, как я описываю; просматривая большую часть документа, необходимо собрать информацию о втором шаге, а затем перемотав документ и пропустив его снова, чтобы разделить его на рабочие места, в идеале выпуская все части документа, которые больше не используются после они были пройдены.
Stax - верный путь. Я бы порекомендовал посмотреть на Woodstox
Вы можете использовать BufferedInputStream
с очень большим размером буфера и использовать mark()
до того, как класс расширения сработает, и reset()
после.
Если части, которые нужны классу расширения, находятся очень далеко от файла, то это может привести к чрезмерному потреблению памяти.
Более общим решением было бы написать свой собственный - BufferedInputStream
аналогичный, который буферизует на диск, если данные, которые должны быть буферизованы, превышают некоторый заданный порог.
Вас может заинтересовать XOM :
XOM довольно уникален тем, что это API с двумя потоковыми / древовидными интерфейсами. Отдельные узлы в дереве могут быть обработаны, пока документ еще строится. Позволяет программам XOM работать почти так же быстро, как основной анализатор может предоставлять данные. Вам не нужно ждать, пока документ будет полностью проанализирован, прежде чем вы сможете начать работать с ним.
XOM очень эффективно использует память. Если вы читаете весь документ в память, XOM использует как можно меньше памяти. Что еще более важно, XOM позволяет вам фильтровать документы по мере их создания, поэтому вам не нужно создавать части дерева, которые вам не интересны. Например, вы можете пропустить построение текстовых узлов, которые представляют только граничный пробел, если такой пробел не имеет значения в вашем приложении. Вы можете даже обработать документ по частям и выбросить каждый кусок, когда закончите с ним. XOM используется для обработки документов размером в гигабайты.
Это звучит как работа для StAX ( JSR 173 ). StAX - это синтаксический анализатор, который означает, что он работает более или менее подобно анализатору на основе событий, например SAX, но у вас больше контроля над тем, когда прекратить чтение, какие элементы извлекать, ...
Удобство использования этого решения будет во многом зависеть от того, что на самом деле делают ваши классы расширения, если у вас есть контроль над их реализацией и т. Д.
Суть в том, что если документ очень большой, вы, вероятно, захотите использовать анализатор событий, а не дерево, поэтому вы не будете использовать много памяти.
Реализации StAX можно найти у SUN ( SJSXP ), Codehaus или нескольких других провайдеров.
Я написал бы специальную реализацию, InputStream
которая расшифровывает байты в файле, а затем использует SAX для анализа полученного XML, когда он выходит из потока.
SAXParserFactory.newInstance().newSAXParser().parse(
new DecryptingInputStream(),
new MyHandler()
);
Посмотрите на библиотеку XOM . Пример, который вы ищете, находится StreamingExampleExtractor.java
в каталоге примеров исходного дистрибутива. Это показывает методику для выполнения потокового анализа большого XML-документа, только создавая определенные узлы, обрабатывая их и отбрасывая их. Это очень похоже на подход саксофона, но имеет гораздо больше встроенных возможностей синтаксического анализа, так что потоковый анализ может быть достигнут довольно легко.
Если вы хотите работать на более высоком уровне, посмотрите на NUX . Это обеспечивает высокоуровневый API потокового xpath, который считывает только объем данных в память, необходимый для оценки xpath.