Logo Море(!) аналитической информации!
IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware
Обучение от Mail.Ru Group.
Онлайн-университет
для программистов с
гарантией трудоустройства.
Набор открыт!

2004 г.

XML в Oracle - это очень просто

Владимир Пржиялковский , преподаватель технологий Oracle

Введение

Тип XMLTYPE появился в Oracle в версии 9.0.  До этого наиболее подходящим для хранения документов в формате XML был тип CLOB (и менее подходящим – тип VARCHAR2, ограниченный максимумом 4000 знаков).  Сам по себе объектный, новый тип XMLTYPE технически может храниться либо по-прежнему в виде CLOB, либо в виде объекта (начиная с версии 9.2).  И еще одно замечание:  несмотря на то, что технологии XML и Java идут «рука об руку», рамки приводимых ниже примеров не требуют от вашей БД установленных возможностей Java.

В этой заметке рассмотрены только логические стороны использования XML в Oracle безотносительно к техническим свойствам хранения и доступа.

Простой пример

CREATE TABLE books
   (id          NUMBER PRIMARY KEY
  , description XMLTYPE);

INSERT INTO books VALUES
    (100
   , XMLTYPE('<cover>
                <title>Oracle SQL*Loader</title>
                <author>Jonathan Gennick</author>
                <author>Sanjay Mishra</author>
                <pages>269</pages>
              </cover>'));

SET long 1000

SELECT id, description FROM books;

SELECT id, b.description.XMLDATA FROM books b;

XMLDATA – специально созданный для XMLTYPE «псевдостолбец». 

XMLTYPE – тип XML

XMLTYPE дает возможность сообщить БД, что заносимый текст – это не просто строка, а строка документа XML.  Следующая попытка приведет к ошибке:

INSERT INTO books VALUES (101, XMLTYPE('<cover><title></title>'));

С дугой стороны, Oracle поймет правильно составленные директивы XML и встроенное в текст описание DTD:

INSERT INTO books VALUES
    (101
   , XMLTYPE('<?xml version="1.0"?>
              <!DOCTYPE cover [
              <!ELEMENT cover (title, author*, pages)>
              <!ELEMENT title (#PCDATA)>
              <!ELEMENT author (#PCDATA)>
              <!ELEMENT pages (#PCDATA)>
              ]
>
              <cover>
                <title>SQL*Plus Pocket Reference</title>
                <author>Jonathan Gennick</author>
                <pages>94</pages>
              </cover>'));

Убедитесь в этом сами, что Oracle действительно соотносит описание DTD самому тексту документа !

Для выборки можно использовать специально придуманные для XMLTYPE функции.  Так, функция EXTRACTVALUE извлекает значения элемента из документа XML:

SELECT id, EXTRACTVALUE(description, '/cover/title')
FROM books;

Функция EXISTSNODE дает возможность использовать в SQL условие отбора XPath (язык отбора, принятый в технологиях XML):

SELECT id, b.description.XMLDATA
FROM books b
WHERE b.description.EXISTSNODE('/cover[author="Sanjay Mishra"]')=1;

XMLTYPE – объектный тип Oracle

Доказательством утверждения в заголовке служит создание следующей таблицы объектов типа XMLTYPE, «таблицы документов XML»:

CREATE TABLE xbooks OF XMLTYPE;

Работать с ними можно, как и с XML-атрибутом в обычной таблице:

INSERT INTO xbooks VALUES
   (XMLTYPE('<cover>
              <title>Oracle SQL*Loader</title>
              <author>Jonathan Gennick</author>
              <author>Sanjay Mishra</author>
              <pages>269</pages>
            </cover>'));

INSERT INTO xbooks VALUES
   (NEW XMLTYPE('<?xml version="1.0"?>
                 <cover>
                   <title>SQL*Plus Pocket Reference</title>
                   <author>Jonathan Gennick</author>
                   <pages>94</pages>
                 </cover>'));

В первом случае объект XML создается с помощью конструктора, а во втором, к тому же, используется оператор NEW.  Последний применяется в Oracle для работы с объектами, однако его использование носит лишь рекомендательный характер, так как в SQL он ничего содержательного не дает.

Далее:

SELECT * FROM xbooks;

SELECT VALUE(x) FROM xbooks x;

SELECT XMLDATA FROM xbooks;

Так же как для таблиц объектов прочих типов, элементы таблицы объектов XML имеют ссылки, то есть позволяют ссылаться на себя через REF в других типах и таблицах:

SELECT REF(x) FROM xbooks x;

SELECT DEREF(REF(x)) FROM xbooks x;

У этого типа нет свойств, но есть методы.  В этом можно убедиться, сделав запрос от имени SYS:

COLUMN text FORMAT A80

SELECT text
FROM user_source
WHERE name ='XMLTYPE' AND type='TYPE'
ORDER BY line;

Исследование каталога rdbms/admin позволяет обнаружить и исходное описание этого типа (но не его тела !) в файле dbmsxmlt.sql.  К сожалению в документации описания этих методов разбросаны по разным местам, не всегда последовательны и ясны.  Так например, EXTRACT и EXISTSNODE (о последней речь шла выше), возведены в ранг функций SQL, то есть описаны в книжке документации по SQL в разделе «Функции», в то время как из предыдущего запроса к словарю-справочнику следует, что это методы.  О том же говорит синтаксис употребления.  Для EXISTSNODE пример уже приводился, а для EXTRACT он может выглядеть так:

SELECT b.description.EXTRACT('/cover/title') FROM books b;

(Сравните с примером использования функции EXTRACTVALUE выше).

Вот некоторые другие примеры методов XMLTYPE:

SELECT b.description.GETCLOBVAL() FROM books b;

SELECT b.description.GETSTRINGVAL() FROM books b;

SELECT b.description.GETROOTELEMENT() FROM books b;

Обратите внимание, что некоторые методы XMLTYPE, например TOOBJECT, могут использоваться только процедурно, так как сами исполнены в виде процедур, а не функций.

Правда, объектность типа XMLTYPE реализована не в полной степени.  Так, попытка создать в таблице столбец из коллекции документов XML (вложенной таблицы или массива VARRAY) в версии 9.2 терпит неудачу.  Это относится только к БД; в PL/SQL этих проблем не возникает:

SQL> declare type xml_nt is table of xmltype index by varchar2(10);
  2  begin null; end;
  3  /

PL/SQL procedure successfully completed.

Взаимные преобразования табличного вида и XMLTYPE

Связь двух форм описания данных – табличной и XML – достигается не одною только возможностью создавать в таблицах столбец типа XMLTYPE.  Возможно преобразование данных из одного вида в другой, благодаря чему исходный формат хранения данных может оказаться не столь существенен. 

Преобразование из XMLTYPE в табличную форму

Для преобразования данных типа XMLTYPE в обычный табличный вид можно использовать функции SQL и методы XMLTYPE, в первую очередь упоминавшуюся метод-функцию EXTRACT:

COLUMN xdoc FORMAT A80

SELECT ROWNUM, id, b.description.EXTRACT('/cover/author') xdoc
FROM books b;

Обратите внимание на возможность и способ обработки нескольких авторов в XML элементах <author>. 

Использование функции SQL EXTRACTVALUE, в свою очередь, оставляет возможность отбора не более одного элемента XML для формирования каждой строки результата SELECT, но зато безболезнено убирает обрамляющие значение элемента XML метки:

SELECT id, EXTRACTVALUE(b.description.EXTRACT('/cover/title'), '/title') xdoc
FROM books b;

То же самое можно записать проще, что уже демонстрировалось в начале статьи.

Преобразование из табличной формы в XMLTYPE

Для обратного преобразования удобно воспользоваться функциями, объединенными в стандарте SQL:2003 названием SQL/XML (другое название – SQLX).  В версии Oracle 9.2 реализованы следующие (не все) функции из этого стандартного набора:

- XMLElement
- XMLAttributes
- XMLAgg
- XMLConcat
- XMLForest

Вот некоторые примеры использования в схеме SCOTT:

SELECT XMLELEMENT("Employee", ename) FROM emp;

SELECT XMLELEMENT("Employee",
          XMLATTRIBUTES(ename AS "Name", empno AS "Number"))
FROM emp;

Обратите внимание, что в результатах выдаются поля типа XMLTYPE:

CREATE TABLE xtable (n) AS SELECT XMLELEMENT("Name", ename) FROM emp;

DESCRIBE xtable

Следующий пример – агрегирующей функции XMLAGG, допускающей использование в запросах с группировкой GROUP BY, подобно тому, как агрегирующие функции MIN, AVG и другие применяются для обычных данных, а не XMLTYPE:

SET LONG 2000

SELECT XMLELEMENT("department", XMLATTRIBUTES(deptno AS "no")),
       XMLAGG(XMLELEMENT("employee", ename))
FROM emp
GROUP BY deptno;

Интересно, что последний запрос допускает создания на своей основе выводимой таблицы, но не базовой:

CREATE VIEW xview (a, b) AS
SELECT XMLELEMENT("department", XMLATTRIBUTES(deptno AS "no")),
       XMLAGG(XMLELEMENT("employee", ename))
FROM emp
GROUP BY deptno;

(срабатывает)

CREATE TABLE xtable (a, b) AS
SELECT XMLELEMENT("department", XMLATTRIBUTES(deptno AS "no")),
       XMLAGG(XMLELEMENT("employee", ename))
FROM emp
GROUP BY deptno;

(ошибка !)

Это объясняется тем, что столбцы A и B в обоих случаях Oracle пытается создавать как XMLTYPE, а наши данные таковы, что в столбце B содержатся строго говоря некорректные строки XML, например

<employee>CLARK</employee><employee>KING</employee> ....

Однако в случае выводимой таблицы Oracle смотрит на это сквозь пальцы, а в случае базовой – нет.  Возможно это есть следствие определенной недоработанности некоторых областей технологий XML в Oracle, что вызвано чересчур быстрыми темпами развития этих технологий.

Новости мира IT:

Архив новостей

Последние комментарии:

Loading

IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

Информация для рекламодателей PR-акции, размещение рекламы — adv@citforum.ru,
тел. +7 985 1945361
Пресс-релизы — pr@citforum.ru
Обратная связь
Информация для авторов
Rambler's Top100 TopList liveinternet.ru: показано число просмотров за 24 часа, посетителей за 24 часа и за сегодня This Web server launched on February 24, 1997
Copyright © 1997-2000 CIT, © 2001-2015 CIT Forum
Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. Подробнее...