Запит XML-даних за допомогою мови XQuery (исходники), Інтеграція додатків і даних, Бази даних, статті

Можливо, ви вже чули про нову архітектуру DB2 Viper, що підтримує як табличну, так і ієрархічну структури даних. Дійсно, в попередніх статтях ми розглядали нові функції DB2 для роботи з XML-даними, розповідали, як створювати об’єкти бази даних і заповнювати їх XML-даними і пояснювали, як працювати з XML-даними за допомогою мов запитів SQL і SQL / XML. У цій статті ми продовжимо вивчення можливостей роботи з XML-даними в програмі DB2, фокусуючись, головним чином, на новій особливості програми – підтримки мови запитів XQuery.


В DB2 мову XQuery розглядається як повноцінна мова, що дозволяє користувачам відразу записувати вирази XQuery, не вимагаючи впровадження або вбудовування виразів XQuery в оболонку пропозицій SQL. Більш того, механізм запитів DB2 обробляє запити XQuery у властивій цій мові системі команд, це означає, що вирази XQuery аналізуються, оцінюються та оптимізуються без прихованої від користувача трансляції на мову SQL. Звичайно, якщо ви захочете написати “двомовний” запит, який містить одночасно вираження XQuery і SQL, DB2 обробить і оптимізує і такі запити.


Як і в статті по SQL / XML “Запит XML-даних в середовищі DB2 за допомогою мови SQL“: У цій статті ви знайдете огляд декількох звичайних для запитів завдань і побачите, як можна використовувати мову XQuery для вирішення цих завдань. Але спочатку коротко розглянемо відмінності мови XQuery від SQL.


Мова XQuery


XQuery багато в чому відрізняється від SQL, головним чином, тому, що ці мови розроблялися для роботи з різними моделями даних, що мають різну структуру. Документ в форматі XML містить ієрархії, для Він характерний внутрішній порядок. Табличні структури даних, підтримувані СУБД на базі SQL, є однорідними і лінійними, рядки, як такі, невпорядковані.


Відмінності між цими моделями даних привели до кількох принципових відмінностей у відповідних їм мовами запитів. Наприклад, XQuery підтримує вираження шляху, що дозволяє програмістам переміщатися по ієрархічній структурі документа XML, в той час як “чистий” SQL (без розширень XML) не допускає такої можливості. XQuery підтримує як типізовані, так і не типізовані дані, а для даних SQL завжди визначений конкретний тип. В XQuery немає нульових значень, оскільки в документах XML відсутні або невідомі дані пропускаються, а SQL, як відомо, використовує нулі для подання відсутніх або невідомих значень даних. XQuery повертає послідовності даних XML; SQL повертає набори результатів, які з різних типів даних SQL.


Це тільки деякі з принципових відмінностей між XQuery і SQL. В рамках цієї вступної статті не наводиться вичерпний список таких відмінностей, але вони будуть детально розглядатися в наступному номері журналу IBM Systems Journal. А зараз давайте перейдемо до вивчення деяких основних аспектів мови XQuery і способів його використання для запиту XML-даних в програмі DB2 Viper.


База даних для вправ


Запити, описані в цій статті, звертаються до прикладів таблиць, створення яких описано в статті “Починаємо працювати з програмою DB2 Viper“. Коротко: лістинг 1 визначає приклади таблиць “items” і “clients”.


Лістинг 1. Визначення таблиць





create table items (
id int primary key not null,
brandname varchar(30),
itemname varchar(30),
sku int,
srp decimal(7,2),
comments xml
)
create table clients(
id int primary key not null,
name varchar(50),
status varchar(10),
contactinfo xml
)

Приклади XML-даних, включених в стовпчик “items comments”, показані на малюнку 1, А приклади XML-дані, включених в стовпчик “clients contactinfo” – на малюнку 2. Наступні приклади запитів будуть посилатися на конкретні елементи одного або відразу обох документів XML.


Рисунок 1. Приклад документа XML збережений в стовпці “comments” таблиці “items”
Приклад документа XML збережений в стовпці


Рисунок 2. Приклад документа XML збережений в стовпці “contactinfo” таблиці “clients”
Приклад документа XML збережений в стовпці


Середа запиту


Всі запити в цій статті розроблені для того, щоб ви могли повторити їх на своєму комп’ютері. Це можна зробити через обробник командного рядка програми DB2 або редактор команд DB2 Command Editor модуля DB2 Control Center. Зображення знімків екрану та інструкції в даній статті відносяться до другого варіанту (DB2 Viper поставляється з середовищем розробника Developer Workbench на базі платформи Eclipse, що може допомогти програмісту конструювати запити наочним способом. У цій статті проблеми розробки додатків в середовищі розробки Developer Workbench не розглядаються).


Для використання редактора команд DB2 Command Editor, відкрийте Control Center та виберіть команду Tools -> Command Editor. На екрані з’явиться вікно, показане на малюнку 3 . У верхній панелі введіть запит, потім натисніть зелену стрілку у верхньому лівому куті, щоб виконати його, і перегляньте отримані результати в нижній панелі або на окремій вкладці “Query Results”.


Рисунок 3. Вікно DB2 Command Editor, яке може бути викликане з DB2 Control Center
Вікно DB2 Command Editor, яке може бути викликане з DB2 Control Center


Приклади запитів XQuery


Як і в статті “Запит XML-даних в середовищі DB2 за допомогою мови SQL“: Тут ми розглянемо кілька найпоширеніших бізнес-сценаріїв і продемонструємо, як використовувати мову XQuery, щоб запит відповідав вимогам для XML-даних. У статті будуть також розглянуті більш складні ситуації, які вимагатимуть впровадження в запит XQuery коду SQL.


В XQuery існує кілька різних видів виразів, які можна комбінувати в будь-яких поєднаннях. Кожен вираз повертає список значень, які можуть бути використані як вихідні дані для інших виразів. Результат того виразу, в яке вкладені всі інші вирази, є результатом всього запиту в цілому.


У цій статті описуються два важливих типа виразів XQuery: це вираження “FLWOR” і вирази шляху. Вирази FLWOR подібні виразами SELECT-FROM-WHERE в SQL – вони використовуються для виконання ітерацій за списком об’єктів і необов’язкового повернення значень, обчислених для кожного об’єкта. Вирази шляху, з іншого боку, переміщаються по ієрархії XML-елементів і повертають ті елементи, які виявлені в кінці шляху.


Подібно висловом SELECT-FROM-WHERE мови запитів SQL, вираз XQuery FLWOR може включати кілька пропозицій, які починаються з певних ключових слів. Для початку пропозицій у вираженні FLWOR використовуються наступні ключові слова:



Вираз шляху в XQuery складається з серії “кроків”, розділених символом “косою риси”. У простій формі, кожен крок веде вниз по ієрархії XML, щоб знайти нащадка для елемента, повернутого на попередньому кроці. Кожен крок у виразі шляху може також містити предикат, який фільтрує елементи, повернуті на цьому кроці, залишаючи тільки ті з них, які задовольняють деяким умовам. Наприклад, уявімо, що змінна $clients обмежена списком XML-документів, що містять елементи , тоді четирехшаговийпроцес вираз шляху $clients/Client/Address[state = “CA”]/zip поверне список поштових індексів клієнтів, що мають каліфорнійські адреси.


У більшості випадків можна написати запит, використовуючи одне з двох виразів – або вираз FLWOR, або вираз шляху.


Використання в DB2 XQuery в якості основного мови запитів


Для виконання запитів XQuery безпосередньо в середовищі DB2 Viper (на відміну від впровадження їх у пропозиції SQL) слід предпославши запиту ключове слово xquery. Це повідомляє DB2 про необхідність викликати для обробки запиту аналізатор мови XQuery. Зверніть увагу, що це потрібно робити тільки в тому випадку, якщо ви використовуєте XQuery в якості верхнеуровневого мови запитів. Якщо ви включаєте вираження XQuery в SQL, немає необхідності випереджати їх ключовим словом xquery. У цій статті мова XQuery використовується в якості основного мови, тому всі запити починаються з xquery.


При виконанні в якості основного мови запитів, XQuery потрібно джерело даних для введення. Один з методів, який XQuery може використовувати, щоб отримати дані для введення, це виклик функції db2-fn:xmlcolumn з параметром, який визначає ім’я таблиці й ім’я стовпця в стовпці XML таблиці DB2. Функція db2-fn:xmlcolumn повертає послідовність документів XML, яка зберігається в даному стовпці. Наприклад, представлений в наступному лістингу запит повертає послідовність документів XML, що містять контактну інформацію клієнтів:


Лістинг 2. Простий запит XQuery, який повертає контактні дані





xquery db2-fn:xmlcolumn(“CLIENTS.CONTACTINFO”)

Згадайте нашу схему бази даних (див. розділ “База даних для вправ“): Ми зберігали такі XML-документи в стовпці” contactinfo “таблиці” clients “. Зверніть увагу, що імена стовпця і таблиці в даному випадку відображаються у верхньому регістрі. Це пояснюється тим, що імена таблиці й стовпці перед записом у внутрішній каталог DB2 зазвичай переводяться у верхній регістр. Мова XQuery є РеЄсТрОзАлЕжНі, тому імена таблиць і стовпців, записані в нижньому регістрі, не відповідали б іменам в каталозі DB2, записаним у верхньому регістрі.


Витяг певних елементів XML


Давайте почнемо з основного завдання. Припустимо, необхідно отримати номери факсів всіх клієнтів, які надали цю інформацію. лістингу 3 описується один з можливих способів складання такого запиту:


Лістинг 3. Пошук даних про номер факсу клієнта за допомогою виразу FLWOR





xquery
for $y in db2-fn:xmlcolumn(“CLIENTS.CONTACTINFO”)/Client/fax
return $y

У першому рядку лістингу міститься вказівка ​​для DB2 про необхідність виклику аналізатора мови XQuery. У наступному рядку DB2 отримує вказівку виконати ітерацію на вкладених елементах елементів Client, містяться в стовпці CLIENTS.CONTACTINFO. Кожен елемент fax по черзі пов’язується зі змінною $ y. Третій рядок показує, що для кожної ітерації повертається значення змінної $ y. Результат являє є послідовність елементів XML, показану в лістингу 4:


Лістинг 4. Приклад виведення даних для попереднього запиту





<fax>4081112222</fax>
<fax>5559998888</fax>

Відступивши від теми, зауважимо, що висновок може також містити деяку інформацію, не представляє великого інтересу для даної статті: версія XML та кодування даних, наприклад, <?xml version=”1.0″ encoding=”windows-1252″ ?>, Та інформація про простір імен XML, наприклад, <fax xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”>. Щоб полегшити вивчення результату запиту, в цій статті ми опускаємо дану інформацію. Тим не менш, вона може бути важливою для деяких додатків XML. Якщо для виконання запиту ви користуєтеся обробником командного рядка програми DB2, ви можете використовувати параметр -d, Щоб приховати інформацію опису XML і параметр -i для виведення результатів на друк в зручному вигляді.


Запит з лістингу 3 міг би виглядати трохи більше лаконічним, якби було вирішено у формі трехшагового вираження шляху, як показано в лістингу 5:


Лістинг 5. Пошук даних про номер факсу клієнта за допомогою виразу шляху




				

db2-fn:xmlcolumn(“CLIENTS.CONTACTINFO”)/Client/fax


Першим кроком вираження шляху здійснюється виклик функції db2-fn:xmlcolumn, Що дозволяє отримати список XML-документів зі стовпця CONTACTINFO таблиці CLIENTS. Другий крок повертає всі елементи Client даного документа, а третій крок – елементи fax, вкладені в елементи Client.


Якщо ви не зацікавлені в отриманні за запитом коду XML-фрагментів, і вам потрібно тільки текстове представлення обраних значень елемента XML, то ви можете включити в пропозицію return функцію text (), Як показано в лістингу 6: Лістинг 6:


Лістинг 6. Два запиту на вибірку текстового представлення даних про номер факсу клієнта





xquery
for $y in db2-fn:xmlcolumn(“CLIENTS.CONTACTINFO”)/Client/fax
return $y/text()
(or)
xquery
db2-fn:xmlcolumn(“CLIENTS.CONTACTINFO”)/Client/fax/text()

Висновок цих запитів може бути приблизно таким, як показано в лістингу 7:


Лістинг 7. Приклад виведення повертаються даних для попереднього запиту





4081112222
5559998888

Результати цих навчальних запитів відносно прості, тому що елемент fax має в основі примітивний тип даних. Безумовно, в основі елементів можуть бути і складні типи, тобто, елементи можуть містити вкладені елементи (або вкладені ієрархії). Елемент Address з контактної інформації нашого клієнта – один з прикладів таких даних. Відповідно до схеми, яка наводиться у статті “Починаємо працювати з програмою DB2 Viper “, цей елемент може містити назву вулиці, номер будинку і квартири, назва міста, штату і поштовий індекс. Подумаємо, які дані повертає запит XQuery в (Лістинг 8) :


Лістинг 8. Запит на вибірку складного типу даних XML за допомогою виразу FLWOR





xquery
for $y in db2-fn:xmlcolumn(“CLIENTS.CONTACTINFO”)/Client/Address
return $y

Якщо ви вирішили, що правильна відповідь – це послідовність фрагментів XML-даних, що містить елементи Address і всі вкладені елементи, то ви не помилилися У лістингу 9 – Приклад такого висновку даних:


Лістинг 9. Приклад виведення повертаються даних для попереднього запиту





<Address>
<street>5401 Julio Ave.</street>
<city>San Jose</city>
<state>CA</state>
<zip>95116</zip>
</Address>
. . .
<Address>
<street>1204 Meridian Ave.</street>
<apt>4A</apt>
<city>San Jose</city>
<state>CA</state>
<zip>95124</zip>
</Address>

Примітка: Даний приклад представлений в форматованому вигляді, щоб полегшити його читання. Редактор команд DB2 Command Editor відображає кожний запис адреси клієнта окремим рядком.


Фільтрація значень елементів XML


Попередні приклади запитів XQuery можна зробити більш виборчими. Для прикладу давайте проаналізуємо, як можна отримати результат, який містить поштові адреси, відповідні поштовим індексом 95116, для всіх клієнтів.


Можна припустити, що пропозиція where запитів XQuery дозволяє виконати фільтрацію результатів за значенням елемента zip в нашому XML-документі. Лістинг 10 показує, як додати пропозицію where до попереднього висловом FLWOR (Лістинг 8) і одержати тільки ті адреси, які нас цікавлять:


Лістинг 10. Вираз FLWOR з новою пропозицією “where”





xquery
for $y in db2-fn:xmlcolumn(“CLIENTS.CONTACTINFO”)/Client/Address
where $y/zip=”95116″
return $y

Доданий вираз where досить просто для розуміння. Пропозиція for пов’язує змінну $ y з кожним повертається адресою по черзі. Пропозиція where містить невелику вираз шляху, яке переміщує фокус запиту від кожного елемента address до вкладеного в нього елементу zip. Пропозиція where істинно (і адреса залишається в результатах запиту) тільки в тому випадку, якщо значення елемента zip одно 95116.


Такий же результат можна отримати, додавши до вираження шляху предикат, як показано в лістингу 11:


Лістинг 11. Вираз шляху, до якого додано фільтруючий предикат





xquery
db2-fn:xmlcolumn(“CLIENTS.CONTACTINFO”)/Client/Address[zip=”95116″]

Звичайно, ви можете вказати в якості умови фільтрації значення поштового індексу, і тоді будуть повернуті елементи незалежно від назви вулиці і номера будинку. Більш того, ви також можете виконати фільтрацію по декільком значенням елементів XML в одному запиті. Наступний запит повертає інформацію про адреси електронної пошти тих клієнтів, чия адреса відповідає конкретному поштовому індексу Нью-Йорка (10011) або будь-яких клієнтів проживають в місті Сан-Хосе.


Лістинг 12. Фільтрація результатів запиту по декількох елементів XML за допомогою виразу FLWOR





xquery
for $y in db2-fn:xmlcolumn(“CLIENTS.CONTACTINFO”)/Client
where $y/Address/zip=”10011″ or $y/Address/city=”San Jose”
return $y/email

Зверніть увагу, що ми змінили пропозицію for, і тепер воно пов’язує змінну $ y не з елементами Address, а з елементами Client. Це дає можливість відфільтрувати елементи Client по одній частині піддереві (Address) і повернути іншу частину піддереві (Email). Вираз шляху в реченні where і пропозиція return можуть бути написані для елемента, який зв’язується з змінної (в нашому випадку, $ y).


Цей самий запит можна зробити більш лаконічним, використовуючи вираз шляху:


Лістинг 13. Фільтрація результатів запиту по декількох елементів XML за допомогою виразу шляху





xquery
db2-fn:xmlcolumn(“CLIENTS.CONTACTINFO”)/Client[Address/zip=”10011″
or Address/city=”San Jose”]/email;

При розгляді цих двох форм запитів не так очевидно те, що будь-яка з них повертає результати, які за двома напрямками істотно відрізняються від тих, які міг би очікувати програміст SQL:



  1. Ви не отримаєте XML-дані на тих відповідають критеріям запиту клієнтів, які не надали свою адресу електронної пошти. Іншими словами, якщо у вас є 1000 клієнтів, що проживають в Сан-Хосе або мають поштовий індекс 10011, а 700 з них надали за однією адресою електронної пошти, ви отримаєте результат у вигляді списку цих 700 адрес електронної пошти. Причина цього криється в принциповому розходженні між мовами XQuery і SQL, про який ми говорили раніше – Xquery не використовує нульові значення.
  2. Ви не дізнаєтеся, які з адрес електронної пошти були витягнуті з одного документа XML. Іншими словами, якщо у вас є 700 клієнтів, що проживають в Сан-Хосе або мають поштовий індекс 10011, і кожен з них вказав по дві адреси електронної пошти, ви отримаєте результат у вигляді списку цих 1400 адрес електронної пошти. Ви не могли б отримати послідовність з 700 записів, кожна з яких включає два електронних адреси.

Будь-яка з двох ситуацій може бути бажаною при одних обставинах і небажаної при інших. Наприклад, якщо вам потрібно надіслати електронною поштою повідомлення кожному відповідному критеріям запиту зареєстрованому клієнту, то ітерація за списком адрес електронної пошти клієнтів у форматі XML може бути виконана в будь-якому додатку. Однак, якщо ви хочете послати строго одне повідомлення кожного клієнта, включаючи і тих, хто надав вам тільки поштова адреса, в цьому випадку описаний раніше запит XQuery не забезпечить потрібного результату.


Існує кілька способів переробити запит таким чином, щоб він повернув результати, які становлять змішану інформацію в одній формі, c зазначенням тих випадків, коли кілька адрес електронної пошти були витягнуті з одного запису про клієнта (тобто, з одного документа XML). Давайте ознайомимося з одним із способів. Але якщо все, чого ви хочете – це отримати список, що містить одну адресу електронної пошти для кожного відповідного критеріям запиту клієнта, вам слід лише злегка змінити пропозицію return в попередньому запиті:


Лістинг 14. Витяг тільки першого елемента email для кожного клієнта





xquery
for $y in db2-fn:xmlcolumn(“CLIENTS.CONTACTINFO”)/Client
where $y/Address/zip=”10011″ or $y/Address/city=”San Jose”
return $y/email[1]

Цей запит змушує DB2 повернути перший з адрес електронної пошти, який вона виявить всередині кожного відповідного критеріям пошуку XML-документа (записи про контактних даних клієнта). Якщо адресу електронної пошти для клієнта, відповідного критеріям запиту, не буде виявлений, то для цього користувача в результаті запиту не буде міститися жодної інформації.


Перетворення виведення XML


Чудова особливість XQuery – це можливість перетворити XML-результат запиту з однієї форми XML в іншу. Наприклад, ви можете використовувати запит XQuery для вибірки всіх або частини збережених документів XML і перетворити висновок в формат HTML, який можна переглянути у веб-браузері. Наступний запит (Лістинг 15) здійснює вибірку адрес клієнтів з сортуванням результатів за поштовим індексом, і перетворює результат в елементи XML, що є частиною неупорядкованого списку HTML:


Лістинг 15. Виконання запиту до DB2 на вибірку XML-даних і повернення результату в форматі HTML





xquery
<ul> {
for $y in db2-fn:xmlcolumn(“CLIENTS.CONTACTINFO”)/Client/Address
order by $y/zip
return <li>{$y}</li>
} </ul>

Запит починається досить просто з ключового слова xquery, яке повідомляє синтаксичному аналізатору DB2, що мова XQuery використовується в якості основного мови. Другий рядок вказує, що в результати слід включити HTML-розмітку для неупорядкованого списку (