Есть ли процессор XPath для модели SAX?
Я ищу оценщик XPath, который не перестраивает весь документ DOM для поиска узлов документа: на самом деле цель состоит в том, чтобы управлять большим объемом данных XML (в идеале более 2 ГБ) с помощью модели SAX, которая очень хорошо подходит для управления памятью и дает возможность поиска узлов.
Спасибо всем за поддержку!
Для всех тех, кто говорит, что это невозможно: я недавно, после того, как задал вопрос, нашел проект с именем "saxpath" ( http://www.saxpath.org/), но я не могу найти ни одного реализующего проекта.
14 ответов
Мой текущий список (составленный из результатов веб-поиска и других ответов):
- http://code.google.com/p/xpath4sax/
- http://spex.sourceforge.net/
- https://github.com/santhosh-tekuri/jlibs/wiki/XMLDog (также содержит диаграмму производительности)
- http://www.cs.umd.edu/projects/xsq/ (проект университета, мертв с 10 лет, GPL)
- MIT-Лицензионный подход http://softwareengineeringcorner.blogspot.com/2012/01/conveniently-processing-large-xml-files.html
- Другие парсеры / модели памяти, поддерживающие быстрый XPath:
- http://vtd-xml.sourceforge.net/ ("Самая быстрая в мире реализация XPath 1.0.")
- http://jaxen.codehaus.org/ (содержит http://www.saxpath.org/)
- http://www.saxonica.com/documentation/sourcedocs/streaming/streamable-xpath.html
Следующим шагом будет использование примеров XMLDog и сравнение производительности всех этих подходов. Затем контрольные примеры следует распространить на поддерживаемые выражения XPath.
Мы регулярно анализируем сложные файлы XML размером 1 ГБ и более, используя синтаксический анализатор SAX, который извлекает частичные деревья DOM, которые можно удобно запрашивать с помощью XPath. Я писал об этом здесь: http://softwareengineeringcorner.blogspot.com/2012/01/conveniently-processing-large-xml-files.html - источники доступны на github - лицензия MIT.
XPath ДОЛЖЕН работать с SAX, и большинство процессоров XSLT (особенно Saxon и Apache Xalan) поддерживают выполнение выражений XPath внутри XSLT в потоке SAX без создания всего dom.
Им удается сделать это, примерно, следующим образом:
- Изучение выражений XPath, которые им нужны
- Получение событий SAX и проверка того, нужен ли этот узел или понадобится одному из выражений XPath.
- Игнорирование события SAX, если оно бесполезно для выражений XPath.
- Буферизация, если это необходимо
Как они буферизуют, это также очень интересно, потому что, в то время как некоторые просто создают фрагменты DOM здесь и там, другие используют очень оптимизированные таблицы для быстрого поиска и уменьшения потребления памяти.
То, насколько им удастся оптимизировать, во многом зависит от типа запросов XPath, которые они находят. Как ясно объясняет уже опубликованная документация Saxon, запросы, которые перемещаются "вверх", а затем проходят "горизонтально" (брат или сестра), очевидно, требуют наличия всего документа, но для большинства из них требуется лишь несколько узлов. Оперативная память в любой момент.
Я почти уверен в этом, потому что, когда я все еще делал веб-приложение каждый день, используя Cocoon, у нас возникала проблема с объемом памяти XSLT каждый раз, когда мы использовали выражение "// что-то" внутри XSLT, и довольно часто нам приходилось переделывать выражения XPath. чтобы лучше оптимизировать SAX.
SAX предназначен только для пересылки, а запросы XPath могут перемещаться по документу в любом направлении (рассмотрим parent::
, ancestor::
, preceding::
а также preceding-sibling::
ось). Я не понимаю, как это вообще возможно. Наилучшим приближением был бы своего рода ленивый DOM, но в зависимости от ваших запросов это может или не может дать вам никакой выгоды - всегда есть запрос наихудшего случая, такой как //*[. != preceding::*]
,
Извините, немного запоздалый ответ здесь - кажется, что это возможно для подмножества XPath - в общем, это очень сложно из-за того, что XPath может соответствовать как вперед, так и назад от "текущей" точки. Мне известны два проекта, которые в некоторой степени решают эту проблему с помощью конечных автоматов: http://spex.sourceforge.net/ & http://www.cs.umd.edu/projects/xsq. Я не смотрел на них подробно, но они, похоже, используют аналогичный подход.
Я добавлю плагин для моего нового проекта под названием AXS. Он находится по адресу https://code.google.com/p/annotation-xpath-sax/ и идея состоит в том, что вы аннотируете методы с помощью операторов XPath (только для прямой оси), и они вызываются, когда анализатор SAX находится на узле это соответствует. Так с документом
<doc>
<nodes>
<node name="a">text of node 1</node>
<node name="b">text of node 2</node>
<node otherattr="I have attributes!">text of node 3</node>
</nodes>
</doc>
вы можете делать такие вещи, как
@XPath("/nodes/node")
void onNode(String nodeText)
{
// will be called with "text of node [123]"
}
или же
@XPathStart("//node[@name='']")
void onNode3(Attrs node3Attrs) { ... }
или же
@XPathEnd("/nodes/node[2]")
void iDontCareAboutNode3() throws SAXExpression
{
throw new StopParsingExpression();
}
Конечно, библиотека настолько новая, что я еще даже не выпустил ее, но она лицензирована MIT, поэтому не стесняйтесь попробовать и посмотреть, соответствует ли она вашим потребностям. (Я написал его для очистки экрана HTML с достаточно низкими требованиями к памяти, чтобы я мог запускать его на старых устройствах Android...) Если вы обнаружите ошибки, сообщите мне об этом, разместив их на сайте googlecode!
Существуют реализации XPath на основе SAX/StAX, но они поддерживают только небольшое подмножество выражений / осей XPath в значительной степени из-за прямой природы SAX/StAX. Лучшая альтернатива, о которой я знаю, - это расширенный VTD-XML, он поддерживает полный xpath, частичная загрузка документов через mem-map.. и максимальный размер документа 256 ГБ, но вам понадобится 64-битная JVM, чтобы использовать его в полной мере
Извините за поздний ответ, но я реализовал простой путь выражения XPath для парсеров SAX. Он поддерживает только тег, атрибут с необязательным значением и индекс из-за прямой природы SAX. Я сделал обработчик делегата для оценки данного выражения, когда обработчик реализует ExpressionFilter. Хотя эти классы встроены в проект, его не должно быть сложно извлечь.
Примеры - см. Классы с HandlerHtml
префикс
Посмотрите на потоковый режим XSLT-процессора Saxon-SA.
http://www.saxonica.com/documentation/sourcedocs/serial.html
"Правила, которые определяют, может ли выражение пути передаваться в потоке:
- Выражение, которое будет транслироваться, начинается с вызова функции document() или doc().
Выражение пути, введенное вызовом doc() или документа, должно соответствовать подмножеству XPath, определенному следующим образом:
любое выражение XPath приемлемо, если оно соответствует правилам для выражений пути, появляющихся в ограничениях идентичности в XML-схеме. Эти правила не допускают предикатов; первый шаг (но только первый) можно ввести с помощью "//"; последний шаг может дополнительно использовать атрибут оси; все остальные шаги должны быть простыми шагами оси с использованием дочерней оси.
- Кроме того, Saxon позволяет выражению содержать объединение, например, doc() / (* / ABC | / XYZ). Союзы также могут быть выражены в сокращенной форме, например, вышеприведенное можно записать как doc() / / (ABC | XYZ).
Выражение должно либо выбирать только элементы, либо только атрибуты, либо смесь элементов и атрибутов.
Простые фильтры (один или несколько) также поддерживаются. Каждый фильтр может применяться к последнему шагу или к выражению в целом, и он должен использовать только нисходящий выбор из узла контекста (оси self, child, attribute, потомок, потомок-или-self или пространства имен). Он не должен быть позиционным (то есть он не должен ссылаться на position() или last() и не должен быть числовым: фактически он должен быть таким, чтобы Saxon мог определить во время компиляции, что он не будет числовым). Фильтры не могут быть применены к союзам или филиалам союзов. Любое нарушение этих условий приводит к тому, что выражение оценивается без оптимизации потоковой передачи.
Эти правила применяются после того, как другие выражения оптимизации были применены к выражению. Например, некоторые выражения FLWOR могут быть переписаны в выражение пути, которое удовлетворяет этим правилам.
Оптимизация включается только в случае явного запроса, либо с помощью функции расширения saxon:stream(), либо с помощью атрибута saxon:read-Once в инструкции xSLT xsl:copy-of или в XQuery pragma saxon:stream. Он доступен только в том случае, если таблица стилей или запрос обрабатывается с использованием Saxon-SA."
Примечание: скорее всего, в коммерческой версии это средство доступно. Раньше я широко использовал Saxon, и это хорошая работа.
Что вы могли бы сделать, это подключить XSL-трансформатор к SAX-источнику входного сигнала Ваша обработка будет последовательной, и препроцессор XSL предпримет попытку перехватить ввод, когда дело доходит до изменения результата, который вы указали. Вы можете использовать это для извлечения значения пути из потока. Это особенно удобно, если вы хотите получить несколько разных результатов XPATH за один проход.
В результате вы получите (как правило) документ XML, но вы можете получить ожидаемый результат, скажем, из StreamResult
не слишком много хлопот.
Ммм, я не знаю, действительно ли я вас понимаю. Насколько я знаю, модель SAX ориентирована на события. Это означает, что вы делаете что-то, если во время синтаксического анализа встречается определенный узел. Да, это лучше для памяти, но я не понимаю, как вы хотели бы получить XPath в него. Поскольку SAX не строит модель, я не думаю, что это возможно.
Вы пробовали также QuiXPath https://code.google.com/p/quixpath/?
Я не думаю, что xpath работает с SAX, но вы можете взглянуть на StAX, который является расширенным потоковым XML API для Java.
Стандартный javax xpath API технически уже работает с потоками; javax.xml.xpath.XPathExpression
можно оценить по InputSource
который, в свою очередь, может быть построен с Reader
, Я не думаю, что это создает DOM под одеялом.