Чтение огромного XML-файла с помощью StAX и XPath
входной файл содержит тысячи транзакций в формате XML, который составляет около 10 ГБ размера. Требование состоит в том, чтобы выбрать каждую транзакцию XML на основе пользовательского ввода и отправить ее в систему обработки.
образец содержимого файла
<transactions>
<txn id="1">
<name> product 1</name>
<price>29.99</price>
</txn>
<txn id="2">
<name> product 2</name>
<price>59.59</price>
</txn>
</transactions>
(техническое)пользователь должен давать имя тега как <txn>
.
мы хотели бы предоставить это решение, чтобы быть более общим. Содержимое файла может отличаться и пользователи могут дать выражение XPath вроде "//transactions/txn
" для выбора отдельных транзакций.
есть несколько технических вещей, которые мы должны рассмотреть здесь
- файл может быть в общем месте или FTP
- поскольку размер файла огромен, мы не можем загрузить весь файл в JVM
можем ли мы использовать парсер StAX для этого сценария? Он должен принимать выражение XPath в качестве входных данных и выбирать/выбирать транзакцию XML.
ищем предложения. Спасибо заранее.
7 ответов
Stax и xpath-очень разные вещи. Stax позволяет анализировать потоковый XML-документ только в прямом направлении. Xpath позволяет анализировать в обоих направлениях. Stax-очень быстрый потоковый XML-парсер, но, если вы хотите xpath, java имеет отдельную библиотеку для этого.
взгляните на этот вопрос для очень похожего обсуждения:есть ли процессор XPath для модели SAX?
если производительность является важным фактором и / или размер документа большой (оба из которых, похоже, имеют место здесь), разница между синтаксическим анализатором событий (например, SAX или StAX) и собственной реализацией Java XPath заключается в том, что последняя создает документ W3C DOM до оценки выражения XPath. [Интересно отметить, что все реализации объектной модели документа Java, такие как DOM или Axiom, используют процессор событий (например, SAX или StAX) для создания представления в памяти, поэтому, если вы можете обойтись только процессором событий, который вы сохраняете как память, так и время, необходимое для создания DOM.]
как я уже упоминал, реализация XPath в JDK работает на документе W3C DOM. Вы можете увидеть это в реализации исходного кода Java JDK, посмотрев на com.sun.org.apache.xpath.internal.jaxp.XPathImpl
, где перед вызовом метода evaluate() синтаксический анализатор должен сначала проанализировать источник:
Document document = getParser().parse( source );
после этого ваш 10GB XML будет представлен в памяти (плюс все, что угодно накладные расходы) - вероятно, не то, что вы хотите. Хотя вам может понадобиться более "общее" решение, и ваш пример XPath, и ваша разметка XML кажутся относительно простыми, поэтому, похоже, нет действительно сильного оправдания для XPath (за исключением, возможно,Программирование элегантность). То же самое было бы верно для предложения XProc: это также построило бы DOM. Если вам действительно нужен DOM, вы можете использовать аксиому, а не W3C DOM. Axiom имеет гораздо более дружелюбный API и строит свой DOM над StAX, поэтому это быстро, и использует Jaxen для своей реализации XPath. Jaxen требует некоторые вид DOM (W3C DOM, DOM4J или JDOM). Это будет верно для всех реализаций XPath, поэтому, если вам действительно не нужно XPath придерживаться только парсера событий, рекомендуется.
SAX-это старый потоковый API, с Stax новее и намного быстрее. Либо используя собственную реализацию JDK StAX (javax.xml.stream
) или Woodstox реализация StAX (что значительно быстрее, по моему опыту), я бы рекомендовал создать фильтр событий XML, который сначала соответствует имени типа элемента (чтобы захватить ваш <txn>
элементов). Это создаст небольшие пакеты событий (элемент, атрибут, текст), которые можно проверить на соответствие пользовательским значениям. После подходящего матча вы можете либо вытащить необходимую информацию из событий, либо передать ограниченные события, чтобы построить мини-дом из них, если вы обнаружили, что результат легче ориентироваться. Но звучит так, будто это перебор. если разметка простая.
это, вероятно, будет самый простой, быстрый возможный подход и избежать накладных расходов памяти при построении DOM. Если вы передали имена элемента и атрибута фильтру (так что ваш алгоритм сопоставления настраивается), вы можете сделать его относительно общим.
это определенно вариант использования XProc с реализацией потоковой и параллельной обработки, такой как QuiXProc (http://code.google.com/p/quixproc)
в этой ситуации, вам придется использовать
<p:for-each>
<p:iteration-source select="//transactions/txn"/>
<!-- you processing on a small file -->
</p:for-each>
вы даже можете обернуть каждое полученное преобразование одной строкой XProc
<p:wrap-sequence wrapper="transactions"/>
надеюсь, что это помогает
мы регулярно анализируем сложные XML-файлы 1GB+ с помощью синтаксического анализатора SAX, который делает именно то, что вы описали: он извлекает частичные деревья DOM, которые можно удобно запросить с помощью XPATH.
я увяз в этом здесь - он использует саксофон, а не парсер StAX, но, возможно, стоит посмотреть.
потоковые преобразования для XML (STX) может быть то, что вам нужно.
вам нужно обработать его быстро или вам нужны быстрые поиски в данных ? Эти требования требуют иного подхода.
для быстрого чтения всего StAX данных будет в порядке.
Если вам нужны быстрые поиски, чем вам может потребоваться загрузить его в некоторую базу данных, Berkeley DB XML, например
забавное решение для обработки огромных XML-файлов >10GB.
- используйте ANTLR для создания смещений байтов для интересующих частей. Это сэкономит некоторую память по сравнению с подходом на основе DOM.
- используйте Jaxb для чтения деталей из байтовой позиции
найдите подробности на примере дампов Википедии (17GB) в этом ответе so https://stackoverflow.com/a/43367629/1485527