Возникла как-то задача расставить идентификаторы для определённого набора объектов в xml БД. Судя по выдаче гугла по этому вопросу или эта задача возникла только у меня, или она на столько тривиальна, что не стоит внимания.
Конкретнее про задачу: есть набор объектов, необходимо добавить к каждому уникальный целый атрибут 'id'. Казалось бы, простая задача (она действительно простая), но сходу решить её не удалось.
Единственное решение, которое мне удалось накопать только 1 раз (потом его нигде не находил) было в подсчёте всех узлов с атрибутом id и добавлению следующему узлу без этого атрибута id со значением count(от всех узлов с атрибутом) + 1. Как можно заметить - решение не самое быстрое и красивое.
Немного покурив xquery, я всё же придумал более оптимальное решение:
Что это такое и почему оно такое страшное? Последние 2 строки очевидны - создаём список нужных узлов и запускаем функцию проставления в ней id'шников.
Теперь про саму функцию. Во-первых, если функция вносит изменения в БД, она должна быть помечена как
возвращает 2 значения. Либо это
либо
Последнее - пустые значения, т.к. если на вход подать пустой объект, произойдёт ошибка исполнения, а сделать 2 return внутри 1 функции нельзя. Поэтому на пустом tail() просто ничего не запускаем. Ещё 2 случая на практике никогда не выполнятся.
Интересней всего то, что такой огород пришлось городить по 2 причинам. Первая - отсутствие возможности просто выполнить функцию - любое действие должно выполняться именно внутри return. Вторая - отсутствие mutable переменных. Самое смешное, что по отдельности ни первая ни вторая причина проблемы бы не вызывали.
Конкретнее про задачу: есть набор объектов, необходимо добавить к каждому уникальный целый атрибут 'id'. Казалось бы, простая задача (она действительно простая), но сходу решить её не удалось.
Единственное решение, которое мне удалось накопать только 1 раз (потом его нигде не находил) было в подсчёте всех узлов с атрибутом id и добавлению следующему узлу без этого атрибута id со значением count(от всех узлов с атрибутом) + 1. Как можно заметить - решение не самое быстрое и красивое.
Немного покурив xquery, я всё же придумал более оптимальное решение:
declare namespace t = 'none';
declare updating function t:setId($arg, $idNum)
{
let $x := head($arg)
return
if( $x ) then
insert node (attribute { 'id2' } {$idNum} ) into $x
else
()
,if( tail($arg) ) then
t:setId(tail($arg), $idNum + 1)
else
()
};
let $i := collection('a_SUITE')/module//object
return t:setId($i, 1)
Что это такое и почему оно такое страшное? Последние 2 строки очевидны - создаём список нужных узлов и запускаем функцию проставления в ней id'шников.
Теперь про саму функцию. Во-первых, если функция вносит изменения в БД, она должна быть помечена как
updating
. Во-вторых, функция может возвращать несколько значений. Т.е. делать return 0, 1 как в питоне. Т.о., конструкцияreturn
if( $x ) then
insert node (attribute { 'id2' } {$idNum} ) into $x
else
()
,if( tail($arg) ) then
t:setId(tail($arg), $idNum + 1)
else
()
возвращает 2 значения. Либо это
insert node (attribute { 'id2' } {$idNum} ) into $x, t:setId(tail($arg), $idNum + 1)
либо
(), ()
Последнее - пустые значения, т.к. если на вход подать пустой объект, произойдёт ошибка исполнения, а сделать 2 return внутри 1 функции нельзя. Поэтому на пустом tail() просто ничего не запускаем. Ещё 2 случая на практике никогда не выполнятся.
Интересней всего то, что такой огород пришлось городить по 2 причинам. Первая - отсутствие возможности просто выполнить функцию - любое действие должно выполняться именно внутри return. Вторая - отсутствие mutable переменных. Самое смешное, что по отдельности ни первая ни вторая причина проблемы бы не вызывали.