Довольно часто мне бывает нужно выделить часть данных по некоторым критериям из файлов формата XML. И каждый раз я писал небольшие скрипты или даже целые Java приложения, которые разбирали XML и анализируя файл выдавали необходимые данные. Сегодня я решил так не делать и попытался воспользоваться стандартом XQuery, предназначенным для выборок данных из XML.
Задача была простая — выбрать из файла Gnucash список счетов (Id, описание) и все транзакции (Описание, с какого счета, на какой счёт, сколько).
Первое на что стоит обратить внимание — очень много реализаций стандарта XQuery и целая куча редакторов. Редакторы есть как онлайн так и для настольных систем с ОС Windows / Linux.
Начал я изучение XQuery со статьи на Wiki, в которой не написано ну совсем ничего полезного. Потом продолжил поиск на w3c и stackoverflow. Кривая поиска вывела меня на довольно годный проприетарный редактор oXygen, его триальную версию я и поставил.
Долго искал как запустить правку XQuery:
- Создать XQuery файл
- Перейти в Window — Open perspective — XQuery Debugger
Получились вот такие небольшие скрипты:
1 2 3 4 5 6 7 8 9 10 11 12 |
declare namespace gnc="http://www.gnucash.org/XML/gnc"; declare namespace book="http://www.gnucash.org/XML/book"; declare namespace act="http://www.gnucash.org/XML/act"; let $root := doc('log.xml') return <accounts> { for $a in $root//gnc-v2/gnc:book/gnc:account return <account name="{$a/act:name/text()}" id="{$a/act:id/text()}"> </account> } </accounts> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
declare namespace gnc="http://www.gnucash.org/XML/gnc"; declare namespace book="http://www.gnucash.org/XML/book"; declare namespace act="http://www.gnucash.org/XML/act"; declare namespace trn="http://www.gnucash.org/XML/trn"; declare namespace ts="http://www.gnucash.org/XML/ts"; declare namespace split="http://www.gnucash.org/XML/split"; let $root := doc('log.xml') return <transactions> { for $t in $root//gnc-v2/gnc:book/gnc:transaction let $splits := $t/trn:splits/trn:split order by $t/trn:date-posted/ts:date ascending return <transaction date="{$t/trn:date-posted/ts:date/text()}" date-entered="{$t/trn:date-entered/ts:date/text()}" summary="{$t/trn:description}" to="{$splits[position() = 1]/split:account/text()}" to-value="{$splits[position() = 1]/split:value/text()}" from="{$splits[position() = 2]/split:account/text()}" from-value="{$splits[position() = 2]/split:value/text()}"/> } </transactions> |
Раздражает необходимость объявления всех используемых пространств имён. Непривычно отсутствие операторных скобок, хотя выражения for могут быть вложенными. Ну а остальное вполне себе съедобно.
Позже я заглянул в IntelliJ Idea и нашёл плагин XQuery Support, который оказался очень удобен для редактирования и отладки.
Общее впечатление как и об XSLT/XSD — ужасный переусложнённый инструмент с небольшими возможностями и огромным зоопарком реализаций. Ну благо что свои задачи решает и работает. Всем советую для вспомогательных задач обработки данных. Только системы на нём не пишите ради всего святого.