XML имеет смысл только как коммуникационных протокол, хранить его - большая ошибка (подробнее вы можете ознакомится с рассуждениями на debank.com). Однако писать код для ввода и вывода XML в реляционное хранилище - тоже лишняя работа, если оно само может принимать и размещать данные в таблицах в соответствии с некоторыми соглашениями. Автор хотел бы вынести на суд свои предложения относительно таких соглашений и заинтересован во мнении, комментариях и возможной реализации этих новшеств. Чертежи представлены в sql5.19.3.pdf , и ниже будут использоваться ссылки на страницы этого документа. Предложения являются дополнением к вопросу о протоколе, поднятым в разделе "Архитектура ОС" статьи "Ошибки и их исправление в эргономике API".
Первое, xml-элемент записывается в одноименную таблицу (т.е. имя тега совпадает с именем таблицы), xml-атрибут - в одноименное поле (имя атрибута совпадает с именем поля). Первичный ключ новой записи заполняется триггером.
Второе, во время создания двух записей, соответствующих родительскому и дочернему xml-элементам, первичный ключ одной копируется во внешний ключ другой. В случае неоднозначности из-за того, что одна таблица ссылается на другую несколькими внешними ключами или две таблицы ссылаются друг на друга одновременно, неоднозначность разрешается в имени открывающего xml-тега: после собственно имени тега ставится знак # и имя нужного ссылающегося поля. Выглядит как новое имя открывающего тега с символом # в середине имени (с.81-83). Закрывающий тег остается без изменений. Будем называть это детерминацией.
Третье, одноименные и не вложенные, а последовательно расположенные xml-элементы превращаются в список записей, т.е. первичный ключ одной записи также копируется во внешний ключ другой. Если таблица ссылается на саму себя несколькими внешними ключами, то неоднозначность также разрешается в имени открывающего xml-тега, только вместо знака # ставится $ (закрывающий тег также остается без изменений). И это также будем называть детерминацией (с.84-85). Примем, что детерминация должна быть указана в каждом из последовательно расположенных одноименных xml-элементов - чтобы пользователю меньше думать. Мы применяем разные знаки - # и $ - чтобы оба вида детерминации можно было использовать одновременно, например, tag#field1$field2
Обратная задача - вывод записей в xml-виде. Использование функций SQL/XML, XQuery, проприетарных веб-серверов (относительно последних подпробнее на lists.xml.org/archives/xml-dev/200802/msg00213.html) дают очень громоздкий код. В то же время как правило извлекаются записи, уже связанные внешним ключом, а значит работа происходит с деревом, уже сформированным в схеме хранилища. Предлагаем в таких случаях лаконичное 'SELECT * FROM a.b.c' для выбора данных из таблиц 'a', 'b', 'c'. Будем называть запись 'a.b.c' термином XTree - по аналогии с XPath.
Если одна таблица ссылается на другую несколькими внешними ключами или две таблицы ссылаются друг на друга одновременно, то после имени таблицы ставится знак # и имя нужного ссылающегося поля. Будем называть это рафинированием. Выглядит как имя таблицы с символом # в середине имени (с.12-14). Аналогично, если таблица, содержащая список, ссылается на саму себя несколькими внешними ключами, то после имени таблицы ставится знак $ и имя нужного ссылающегося поля. Это также будем называть рафинированием (с.15-16). Оба вида рафинирования можно использовать одновременно, например, table#field1$field2
Как записать детерминацию и рафинирование при нескольких ссылающихся полях? Перечислим ситуации.
Распорка (nog) - соединение двумя внешними ключами трех таблиц, причем ссылающиеся поля находятся в одной промежуточной таблице.
create table a ( id num primary key, data float ); create table b ( id num primary key, ref1 num references a(id), -- нужно ref2 num references a(id), -- не нужно ref3 num references c(id), -- нужно ref4 num references c(id), -- не нужно data float ); create table c ( id num primary key, data float );И в детерминации, и в рафинировании ссылающиеся поля указываются через двоеточие; таблица-предок упоминается первой, потомок - второй (ссылающиеся поля могут быть одноименными). Таким образом ввод выглядит как
<a> <b#ref1:ref3> <c> </b> </a>вывод (XTree) как
create table a ( id num primary key, ref1 num references b(id), -- нужно ref2 num references b(id), -- не нужно data float ); create table b ( id num primary key, data float ); create table c ( id num primary key, ref1 num references b(id), -- нужно ref2 num references b(id), -- не нужно data float );Соответственно ввод
<a#ref1> <b> <c#ref3> </b> </a>вывод
create table a ( id num primary key, ref num references b(id), data float ); create table b ( id num primary key, lnk num references a(id), data float );В этом случае мы можем полагать родительской таблицей как одну, так и другую. Поэтому ввести можно двумя способами
<a#ref> <b> </a>и
<a> <b#lnk> </a>XTree и XPath также две пары
create table a ( id num primary key, data float ); create table b ( id num primary key, ref1 num references a(id), -- нужно ref2 num references a(id), -- не нужно data float ); create table c ( id num primary key, ref1 num references a(id), -- нужно ref2 num references a(id), -- не нужно data float );Входящий XML выглядит как
<a> <b#ref1> <c#ref1> </a>а вот XTree и XPath имеют два варианта, ведь предикат может требовать дерево как со всеми ветвями, так и только с одной. Со всеми - это
create table a ( id num primary key, ref1 num references b(id), -- нужно ref2 num references b(id), -- не нужно ref3 num references c(id), -- нужно ref4 num references c(id), -- не нужно data float ); create table b ( id num primary key, data float ); create table c ( id num primary key, data float );Здесь ввод
<a#ref1+ref3> <b> <c> </a>вывод и маршрут с требованием записей во всех дочерних таблицах есть
create table b ( id num primary key, data float ); create table c ( id num primary key, data float ); create table d ( id num primary key, ref1 num references b(id), -- нужно ref2 num references b(id), -- не нужно ref3 num references c(id), -- нужно ref4 num references c(id), -- не нужно data float );Чтобы работа происходила, только если существуют все возможные xml-деревья, мы пишем
create table b ( id num primary key, ref1 num references d(id), -- нужно ref2 num references d(id), -- не нужно data float ); create table c ( id num primary key, ref1 num references d(id), -- нужно ref2 num references d(id), -- не нужно data float ); create table d ( id num primary key, data float );Ну, в общем-то все то же самое - в смысле
Во всех ситуациях ссылающиеся поля составных внешних ключей будем перечислять через знак умножения. В вводе это выглядит как
<a> <b#lnk1*lnk2> </a>в выводе и маршруте - как
Дмитрий Тюрин (DmitryTurin.narod.ru):
dima.turin@centrum.cz
(все письма из домена .ru попадают в спам),
dima.turin@gmail.com