Классика баз данных - статьи

       

Функциональные update-выражения


Для преодоления указанных проблем мы предлагаем расширить язык XQuery функциональными update-выражениями. Функциональные update-выражения составляют язык модификации XML-данных с функциональной семантикой. Основная идея функциональных update-выражений состоит в том, что в них используется синтаксис, близкий к синтаксису традиционных update-выраженияй, но они выполняются без побочных эффектов. В отличие от обычных update-выражений, функциональные update-выражения не изменяют состояние данных, а возвращают копию данных с измененным состоянием.

Компактность и выразительность функциональных update-выражений достигается благодаря использованию синтаксиса, близкого к традиционным update-выражениям. Результатом вычисления функциональных update-выражений являются XML-данные, то есть такие выражения не расширяют модель данных языка XQuery и, следовательно, могут быть естественным образом включены в состав выражений языка XQuery.

Рассмотрим синтаксис и семантику функциональных update-выражений на примерах, описанных во введении. В первом примере требовалось вернуть XHTML-представления обзоров кинофильмов в жанре fiction, заменив все вхождения элемента director соответствующей гиперссылкой. Такой запрос, записанный при помощи функциональных update-выражений, выглядит следующим образом:

for $r in doc("db.xml")/db/movie[gender="fiction"]/review transform replace $d in $r//director with

<a href="{doc("b")//person[name=$d/@name]/homepage/text()}"> {$d/text()} </a>

Запрос 3. Получение HTML-представления обзоров кинофильмов в жанре fiction с использованием функциональных update-выражений

Данное функциональное update-выражение следует интерпретировать следующим образом. Конструкция for связывает XQuery-переменную $r с последовательностью XML-узлов, возвращаемой XPath-выражением, которое следует за ключевым словом in. В функциональном update-выражении ветка for, помимо связывания переменной с последовательностью XML-узлов, определяет результат выражения, то есть новые узлы, которые будут являться результатом вычисления всего выражения.
В данном примере результатом вычисления выражения будет последовательность узлов review. Возвращаемые элементы review представляют собой копию узлов review оригинального документа с модификациями, описанными в конструкции transform replace функционального update-выражения. В данном примере запрос описывает трансформацию данных из класса "найти и заменить". Переменная $d связывается с узлами, расположенными внутри возвращаемого элемента review. Каждое из таких связываний в возвращаемом элементе заменяется на новый элемент, описываемый XQuery-конструктором. Таким образом, в примере функциональное update-выражение возвращает последовательность узлов review, в которых все вхождения элемента director заменены элементом a. Выражение вычисляется без побочных эффектов, т.е. узлы review документа db.xml не изменяются.

Рассмотрим второй пример из предыдущей главы. Нам требуется выполнить запрос над XML-данными с известной схемой данных, ориентированными на хранение данных. Логика запроса заключается в выборке всех заказов с ценой, конвертированной в другую валюту. Ниже представлена запись такого запроса с использованием функциональных update-выражений.

let $euro-rate:=doc("rates")/rates/rate[@name="euro"]/text() for $orders in doc("orders.xml")/orders transform replace $p in $orders/order/orderLine/price with <price>{$p/text()*$euro-rate}</price>

Запрос 4. Получение списка заказов с конвертированной ценой с использованием функциональных update-выражений

По синтаксису и семантике запрос аналогичен предыдущему запросу. Отличия заключаются в двух аспектах. Во-первых, вследствие известной схемы данных, все XPath-выражения прописаны без использования оси descendant-or-self []. Второе, более принципиальное отличие состоит в том, что запрос возвращает один элемент orders, в котором все вложенные элементы order изменены требуемым образом. Так происходит вследствие того, что XPath выражение doc("orders.xml")/orders возвращает только один элемент orders.



Как уже отмечалось выше, функциональное update-выражение может возвращать любые данные из модели данных языка XQuery. В предыдущих примерах результатом вычисления выражений были последовательности узлов элементов XML-документа. Необходимо подчеркнуть, что функциональное update-выражение может возвращать и узел документа. Предыдущий пример (Запрос 4), модифицированный соответствующим образом, представлен ниже (Запрос 5).

let $euro-rate:=doc("rates")/rates/rate[@name="euro"]/text() for $orders in doc("orders.xml") transform replace $p in $orders/orders/order/orderLine/price with <price>{$p/text()*$euro-rate}</price>

Запрос 5. Получение узла XML-документа orders.xml с конвертированной ценой с использованием функциональных update-выражений

Функциональные update-выражения естественным образом расширяют язык XQuery и не нарушают его замкнутости. В сложных XQuery-запросах, update-выражения с функциональной семантикой могут участвовать равноправно по отношению к выражениями языка XQuery. Благодаря этому принципиальной особенностью расширения языка XQuery функциональными update-выражениями является доступность в одном XQuery-выражении как исходного, так и модифицированного состояния XML-данных.

Последняя возможность может требоваться в целом ряде случаев . Например, такая потребность возникает при необходимости произвести некоторую аналитику над возможным изменением данных, то есть проанализировать изменения по отношению к текущему состоянию данных относительно некоторого модифицированного состояния.

В примере Запрос 6 выражение на расширенном языке конструирует сводные XML-данные над исходным и модифицированным состояниями данных. Несмотря на то, что этот запрос может быть относительно просто выражен средствами языка XQuery, в практических приложениях его запись в представленном виде может быть более приемлемой.

let $euro-rate:=document("stock")/rates/euro/text() let $orders:=document("orders")/orders/order let $new-orders:=for $o in document("orders")/orders/order transform replace $p in $o//price with <price> {$p/@euro-price/text() * $euro-rate} </price>

return <price-change> <initial>{sum($orders/price/text()}</initial> <new>{sum($new-orders/price/text()}</new> </price-change>

Запрос 6. Использование в одном запросе исходного и модифицированного состояний данных


Содержание раздела