Возникла как-то задача расставить идентификаторы для определённого набора объектов в 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 переменных. Самое смешное, что по отдельности ни первая ни вторая причина проблемы бы не вызывали.
А зачем понадобилось расставлять id?
ОтветитьУдалитьПо-моему к узлу или классу узлов всегда можно обратиться через xpath.
1. У тебя могут быть 2 разных узла с одинаковым набором атрибутов и их надо как-то различать. Можно конечно отслеживать путь, по которому они лежат, но это неудобно.
Удалить2. Отображение связи 2 узлов. В моём конкретном случае - связь между реализацией и и вызовом функции.
3. Ускорение поиска. Например, если в реализации функции указан id="10", то ты можешь быстро запросить все реализации с таким id из индекса. По имени не получится либо по причине 1, либо потому что runtime оптимизатор запросов может тупить.
1) -> :first, :second, :nth(1), :last
ОтветитьУдалить2)
3) в браузерах запрос по id крайне медленный (почему, я пока не понимаю) + в рамках одного xml id обязан быть уникальным (или у тебя xml не один), но мысль понял.
Если не лениво, расскажи, в каком контексте ты это все используешь и как оно работает.
Ну, для моих целей оно, видимо, не особо подходит. Предполагалось, что я буду представлять AST программы в xml формате и обрабатывать при помощи native-xml БД.
УдалитьОдин из примеров использования id'шника: идёшь по ходу выполнения программы, у тебя встречается вызов функции. Без id придётся каждый раз выполнять поисковый запрос, а это может быть весьма долго.
> в браузерах запрос по id крайне медленный
Насчёт скорости - может быть много причин. Нужно смотреть запрос + быть уверенным, что было включено индексирование + быть уверенным, что оно используется. Кстати, а почему именно по id? Оно чем-то отличается от обычного атрибута?
Вообще, в xquery есть функция generate-id(), но она возвращает не целое значение, а строку и она не везде реализована.
Тем что он обязан быть уникальным, и то что к нему возможна абсолютная адресация через css\js. Еще абсолютная адресация есть для class. Но для id один к одному для элемента, для класса это многие ко многим. И то и другое грубо говоря семантическое имя элемента.
ОтветитьУдалить[ul]
[li class="even" id="fst"]
[li class="odd veryimportant"]
[li class="even"]
[li class="odd" id="lst"]
[/ul]