Как преобразовать огромные XML-файлы в Java?

Поскольку в заголовке говорится это, у меня есть огромный XML-файл (ГБ)

<root>  
<keep>  
   <stuff>  ...  </stuff>  
   <morestuff> ... </morestuff>  
</keep>  
<discard>  
   <stuff>  ...  </stuff>  
   <morestuff> ... </morestuff>
</discard>  
</root>  

и я хотел бы преобразовать его в намного меньший, который сохраняет только несколько элементов.
Мой синтаксический анализатор должен сделать следующее:
1. Синтаксический анализ через файл до соответствующего элемента запускается.
2. Скопируйте целый соответствующий элемент (с детьми) к выходному файлу. перейдите в 1.

шаг 1 легок с SAX и невозможен для DOM-синтаксических-анализаторов.
шаг 2 является раздражающим с SAX, но легким с DOM-синтаксическим-анализатором или XSLT.

и что? - там аккуратный способ объединить SAX и DOM-синтаксический-анализатор, чтобы сделать задачу?

8
задан user306708 5 May 2010 в 13:46
поделиться

7 ответов

Да, просто напишите обработчик содержимого SAX, и когда он встретит определенный элемент, вы построите на нем дерево доменов. Я делал это с очень большими файлами, и это работает очень хорошо.

На самом деле это очень просто: как только вы встречаетесь с началом нужного элемента, вы устанавливаете флаг в своем обработчике контента, и с этого момента вы перенаправляете все в построитель DOM. Когда вы встречаетесь с концом элемента, вы устанавливаете флаг в false и записываете результат.

(Для более сложных случаев с вложенными элементами с одним и тем же именем элемента вам потребуется создать стек или счетчик, но это все еще довольно легко сделать.)

9
ответ дан 5 December 2019 в 05:25
поделиться

StAX может показаться очевидным решением: это извлекающий синтаксический анализатор, а не «выталкивание» SAX или «буферизация всего вещь »подход DOM. Не могу сказать, что использовал его. Может пригодиться поиск «Учебник StAX» :)

10
ответ дан 5 December 2019 в 05:25
поделиться

Поскольку вы говорите о ГБ, я бы предпочел уделить приоритетное внимание использованию памяти при рассмотрении. SAX требуется примерно в 2 раза больше памяти, чем размер документа, в то время как DOM требуется, чтобы он был как минимум 5 раз. Итак, если ваш XML-файл имеет размер 1 ГБ, то для DOM потребуется минимум 5 ГБ свободной памяти. Это уже не смешно. Так что SAX (или любой его вариант, например StAX) - лучший вариант.

Если вы хотите максимально эффективно использовать память, посмотрите VTD-XML . Для этого требуется лишь немного памяти больше, чем размер файла.

3
ответ дан 5 December 2019 в 05:25
поделиться

Взгляните на StAX , это может быть то, что вам нужно. Есть хорошее введение в IBM Developer Works .

2
ответ дан 5 December 2019 в 05:25
поделиться

Я получил хороший опыт работы с STX (Streaming Transformations for XML). По сути, это потоковая версия XSLT, хорошо подходящая для разбора огромных объемов данных с минимальными затратами памяти. Она имеет реализацию на Java под названием Joost.

Должно быть легко придумать преобразование STX, которое игнорирует все элементы, пока элемент не совпадет с заданным XPath, копирует этот элемент и все его дочерние элементы (используя шаблон идентичности в группе шаблонов) и продолжает игнорировать элементы до следующего совпадения.

UPDATE

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

<stx:transform xmlns:stx="http://stx.sourceforge.net/2002/ns"
    version="1.0" pass-through="none" output-method="xml">
    <stx:template match="element/child">
        <stx:process-self group="copy" />
    </stx:template>
    <stx:group name="copy" pass-through="all">
    </stx:group>
</stx:transform>

Параметр pass-through="none" в stx:transform настраивает шаблоны по умолчанию (для узлов, атрибутов и т.д.) так, чтобы они не производили никакого вывода, но обрабатывали дочерние элементы. Затем stx:template соответствует XPath element/child (это место, где вы помещаете ваше выражение соответствия), он "обрабатывает себя" в группе "copy", что означает, что соответствующий шаблон из группы name="copy" вызывается на текущем элементе. Эта группа имеет pass-though="all", поэтому шаблоны по умолчанию копируют свои входные данные и обрабатывают дочерние элементы. Когда элемент element/child завершается, управление передается обратно шаблону, который вызвал process-self, и следующие элементы снова игнорируются. Пока шаблон снова не совпадет.

Ниже приведен пример входного файла:

<root>
    <child attribute="no-parent, so no copy">
    </child>
    <element id="id1">
        <child attribute="value1">
            text1<b>bold</b>
        </child>
    </element>
    <element id="id2">
        <child attribute="value2">
            text2
            <x:childX xmlns:x="http://x.example.com/x">
            <!-- comment -->
                yet more<b i="i" x:i="x-i" ></b>
            </x:childX>
        </child>
    </element>
</root>

Вот соответствующий выходной файл:

<?xml version="1.0" encoding="UTF-8"?>
<child attribute="value1">
            text1<b>bold</b>
        </child><child attribute="value2">
            text2
            <x:childX xmlns:x="http://x.example.com/x">
            <!-- comment -->
                yet more<b i="i" x:i="x-i" />
            </x:childX>
        </child>

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

5
ответ дан 5 December 2019 в 05:25
поделиться

Для такого большого XML-документа идеально подошло бы что-то с потоковой архитектурой, например Omnimark.

Это также не должно быть чем-то сложным. Скрипт Omnimark, подобный приведенному ниже, может дать то, что вам нужно:

process

submit #main-input

macro upto (arg string) is
    ((lookahead not string) any)*
macro-end

find (("<keep") upto ("</keep>") "</keep>")=>keep
    output keep

find any
2
ответ дан 5 December 2019 в 05:25
поделиться

Вы можете сделать это довольно легко с помощью XMLEventReader и нескольких XMLEventWriterов из пакета javax.xml.stream.

0
ответ дан 5 December 2019 в 05:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: