Функции XML

Функции и подобные им выражения, описанные в этом разделе, работают со значениями типа xml. Информацию о типе xml см. в разделе Тип XML. Подобные функциям выражения xmlparse и xmlserialize, преобразовывающие значения в тип xml и из него, описаны там, а не в этом разделе.

Использование большинства этих функций требует, чтобы QHB была собрана с флагом соответствующей библиотеки (configure --with-libxml).



Создание XML-контента

Для создания XML-контента из данных SQL существует набор функций и подобных им выражений. Соответственно, они особенно подходят для форматирования результатов запросов в XML-документы для обработки в клиентских приложениях.

xmlcomment

xmlcomment ( text ) → xml

Функция xmlcomment создает значение XML, содержащее комментарий XML с заданным текстом. Текст не может содержать «--» или заканчиваться на «-», иначе полученная конструкция не будет допустимым комментарием XML. Если аргумент равен NULL, результат тоже будет NULL.

Пример:

SELECT xmlcomment('hello');

  xmlcomment
--------------
 <!--hello-->

xmlconcat

xmlconcat ( xml [, ...] ) → xml

Функция xmlconcat конкатенирует список отдельных значений XML, выдавая одно значение, содержащее фрагмент содержимого XML. Значения NULL отбрасываются; результат будет NULL, только если все аргументы равны NULL.

Пример:

SELECT xmlconcat('<abc/>', '<bar>foo</bar>');

      xmlconcat
----------------------
 <abc/><bar>foo</bar>

Объявления XML, если они есть, объединяются следующим образом. Если все значения аргументов имеют объявление одной версии XML, эта версия используется в результате, иначе версия вообще не используется. Если у всех значений аргумента имеется объявление standalone со значением «yes», то это же значение используется в результате. Если у всех значений аргумента имеется объявление standalone и по крайней мере одно из них равно «no», тогда в результате используется это значение. Иначе у результата не будет объявления standalone. Если определено, что в результате должно быть объявление standalone, но нет объявления версии, будет выведена версия 1.0, поскольку для XML требуется, чтобы объявление XML содержало объявление версии. Объявления кодировок игнорируются и удаляются во всех случаях.

Пример:

SELECT xmlconcat('<?xml version="1.1"?><foo/>', '<?xml version="1.1" standalone="no"?><bar/>');

             xmlconcat
-----------------------------------
 <?xml version="1.1"?><foo/><bar/>

xmlelement

xmlelement ( NAME имя [, XMLATTRIBUTES ( значение_атрибута [ AS имя_атрибута ] [, ...] ) ] [, содержимое [, ...]] ) → xml

Выражение xmlelement создает элемент XML с заданным именем, атрибутами и содержимым. Показанные в синтаксисе элементы имя и имя_атрибута представляют собой простые идентификаторы, а не значения. Элементы значение_атрибута и содержимое являются выражениями, которые могут выдавать любой тип данных QHB. Аргументы внутри XMLATTRIBUTES генерируют атрибуты элемента XML; значения содержимого конкатенируют с ними, формируя содержимое элемента.

Примеры:

SELECT xmlelement(name foo);

 xmlelement
------------
 <foo/>

SELECT xmlelement(name foo, xmlattributes('xyz' as bar));

    xmlelement
------------------
 <foo bar="xyz"/>

SELECT xmlelement(name foo, xmlattributes(current_date as bar), 'cont', 'ent');

             xmlelement
-------------------------------------
 <foo bar="2007-01-26">content</foo>

Имена элементов и атрибутов, недопустимые в XML, экранируются путем замены нарушающих символов последовательностью _xHHHH_, где HHHH — это кодовая точка символа Unicode в шестнадцатеричной записи. Например:

SELECT xmlelement(name "foo$bar", xmlattributes('xyz' as "a&b"));

            xmlelement
----------------------------------
 <foo_x0024_bar a_x0026_b="xyz"/>

Если значение атрибута является ссылкой на столбец, то указывать явно имя атрибута необязательно — в качестве этого имени по умолчанию будет использовано имя столбца. В остальных случаях атрибуту нужно явно задать имя. Поэтому этот пример применим:

CREATE TABLE test (a xml, b xml);
SELECT xmlelement(name test, xmlattributes(a, b)) FROM test;

А эти — нет:

SELECT xmlelement(name test, xmlattributes('constant'), a, b) FROM test;
SELECT xmlelement(name test, xmlattributes(func(a, b))) FROM test;

Содержимое элемента, если оно задано, будет отформатировано в соответствии с его типом данных. Если само содержимое имеет тип xml, есть возможность конструировать сложные XML-документы. Например:

SELECT xmlelement(name foo, xmlattributes('xyz' as bar),
                            xmlelement(name abc),
                            xmlcomment('test'),
                            xmlelement(name xyz));

                  xmlelement
----------------------------------------------
 <foo bar="xyz"><abc/><!--test--><xyz/></foo>

Содержимое других типов будет отформатировано в допустимые символьные данные XML. В частности, это означает, что символы <, > и & будут преобразованы в сущностные объекты. Двоичные данные (тип данных bytea) будут представлены в кодировке base64 или в шестнадцатеричной кодировке, в зависимости от настройки параметра конфигурации xmlbinary. Как ожидается, конкретное поведение для отдельных типов данных будет развиваться, чтобы согласовать сопоставления QHB с сопоставлениями, указанными в стандарте SQL:2006 и новее, как описано в подразделе Сопоставления типов данных и значений между SQL и XML.


xmlforest

xmlforest ( содержимое [ AS имя ] [, ...] ) → xml

Выражение xmlforest создает XML-лес (последовательность) элементов, используя заданные имена и содержимое. Как и в выражении xmlelement, каждое имя должно быть простым идентификатором, тогда как выражения содержимое могут иметь любой тип данных.

Примеры:

SELECT xmlforest('abc' AS foo, 123 AS bar);

          xmlforest
------------------------------
 <foo>abc</foo><bar>123</bar>


SELECT xmlforest(table_name, column_name)
FROM information_schema.columns
WHERE table_schema = 'pg_catalog';

                                         xmlforest
-------------------------------------------------------------------------------------------
 <table_name>pg_authid</table_name><column_name>rolname</column_name>
 <table_name>pg_authid</table_name><column_name>rolsuper</column_name>
 ...

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

Имена элементов, недопустимые в XML, экранируются, как показано выше для выражения xmlelement. Точно так же данные содержимого экранируются, делая его допустимым для XML (за исключением тех данные, которые уже имеют тип xml).

Обратите внимание, что XML-леса не являются допустимыми документами XML, если они состоят из более чем одного элемента, поэтому может быть полезно вложить выражения xmlforest в xmlelement.


xmlpi

xmlpi ( NAME имя [, содержимое ] ) → xml

Выражение xmlpi создает инструкцию по обработке XML. Как и в выражении xmlelement, имя должно быть простым идентификатором, тогда как выражение содержимое может иметь любой тип данных. Это содержимое, если оно задано, не должно содержать последовательность символов ?>.

Пример:

SELECT xmlpi(name php, 'echo "hello world";');

            xmlpi
-----------------------------
 <?php echo "hello world";?>

xmlroot

xmlroot ( xml, VERSION {text|NO VALUE} [, STANDALONE {YES|NO|NO VALUE} ] ) → xml

Выражение xmlroot изменяет свойства корневого узла значения XML. Если задается версия, она заменяет значение в объявлении версии корневого узла; если задается значение параметра standalone, оно заменяет значение в объявлении standalone корневого узла.

SELECT xmlroot(xmlparse(document '<?xml version="1.1"?><content>abc</content>'),
               version '1.0', standalone yes);

                xmlroot
----------------------------------------
 <?xml version="1.0" standalone="yes"?>
 <content>abc</content>

xmlagg

xmlagg ( xml ) → xml

Функция xmlagg, в отличие от других описанных здесь функций, является агрегатной. Он конкатенирует входные значения с вызовом агрегатной функции, во многом подобно xmlconcat, за исключением того, что конкатенация затрагивает строки, а не выражения в одной строке. Дополнительную информацию об агрегатных функциях см. в разделе Агрегатные функции.

Пример:

CREATE TABLE test (y int, x xml);
INSERT INTO test VALUES (1, '<foo>abc</foo>');
INSERT INTO test VALUES (2, '<bar/>');
SELECT xmlagg(x) FROM test;
        xmlagg
----------------------
 <foo>abc</foo><bar/>

Чтобы определить порядок конкатенации, в агрегатный вызов можно добавить предложение ORDER BY, как описано в подразделе Агрегатные выражения. Например:

SELECT xmlagg(x ORDER BY y DESC) FROM test;
        xmlagg
----------------------
 <bar/><foo>abc</foo>

Следующий нестандартный подход рекомендовался в предыдущих версиях и по-прежнему может быть полезен в определенных случаях:

SELECT xmlagg(x) FROM (SELECT * FROM test ORDER BY y DESC) AS tab;
        xmlagg
----------------------
 <bar/><foo>abc</foo>


Предикаты XML

Выражения, описанные в этом разделе, проверяют свойства значений типа xml.

IS DOCUMENT

xml IS DOCUMENT → boolean

Выражение IS DOCUMENT возвращает true, если значение аргумента XML является правильным документом XML, false, если это не так (то есть если это фрагмент содержимого), или NULL, если аргумент равен NULL. Разница между документами и фрагментами содержимого описана в разделе Тип XML.


IS NOT DOCUMENT

xml IS NOT DOCUMENT → boolean

Выражение IS NOT DOCUMENT возвращает false, если значение аргумента XML является правильным документом XML, true, если это не так (то есть если это фрагмент содержимого), или NULL, если аргумент равен NULL.


XMLEXISTS

XMLEXISTS ( text PASSING [BY {REF|VALUE}] xml [BY {REF|VALUE}] ) → boolean

Функция xmlexists вычисляет выражение XPath 1.0 (первый аргумент), используя в качестве элемента контекста переданное значение XML. Функция возвращает false, если в результате этого вычисления выдается пустой набор узлов, true, если выдается любое другое значение, или NULL, если любой аргумент равен NULL. Отличное от NULL значение, передаваемое в качестве элемента контекста, должно быть документом XML, а не фрагментом содержимого или любым значением, отличным от XML.

Пример:

SELECT xmlexists('//town[text() = ''Toronto'']' PASSING BY VALUE '<towns><town>Toronto</town><town>Ottawa</town></towns>');

 xmlexists
------------
 t
(1 row)

Предложения BY REF и BY VALUE в QHB принимаются, но игнорируются (это рассматривается в подразделе Непреднамеренные ограничения реализации).

В стандарте SQL функция xmlexists вычисляет выражения на языке XML Query, но QHB допускает только выражение XPath 1.0 (это рассматривается в подразделе Запросы ограничены XPath 1.0).


xml_is_well_formed

xml_is_well_formed ( text ) → boolean
xml_is_well_formed_document ( text ) → boolean
xml_is_well_formed_content ( text ) → boolean

Эти функции проверяют, представляет ли строка типа text синтаксически корректным XML, возвращая логический результат. Функция xml_is_well_formed_document проверяет аргумент как синтаксически корректный документ, а функция xml_is_well_formed_content — как синтаксически корректное содержимое. Функция xml_is_well_formed выполняет первое, если в параметре конфигурации xmloption задано значение DOCUMENT, или второе, если задано CONTENT. Это означает, что xml_is_well_formed полезна для определения успешности простого приведения к типу xml, тогда как две другие функции полезны для определения того, будут ли успешными соответствующие варианты XMLPARSE.

Примеры:

SET xmloption TO DOCUMENT;
SELECT xml_is_well_formed('<>');
 xml_is_well_formed
--------------------
 f
(1 row)

SELECT xml_is_well_formed('<abc/>');
 xml_is_well_formed
--------------------
 t
(1 row)

SET xmloption TO CONTENT;
SELECT xml_is_well_formed('abc');
 xml_is_well_formed
--------------------
 t
(1 row)

SELECT xml_is_well_formed_document('<pg:foo xmlns:pg="http://postgresql.org/stuff">bar</pg:foo>');
 xml_is_well_formed_document
-----------------------------
 t
(1 row)

SELECT xml_is_well_formed_document('<pg:foo xmlns:pg="http://postgresql.org/stuff">bar</my:foo>');
 xml_is_well_formed_document
-----------------------------
 f
(1 row)

Последний пример показывает, что при проверке учитывается корректное сопоставление пространств имен.



Обработка XML

Для обработки значений типа данных xml QHB предлагает функции xpath и xpath_exists, которые вычисляют выражения XPath 1.0, и табличную функцию XMLTABLE.

xpath

xpath ( xpath text, xml xml [, массив_пространств_имен text[] ] ) → xml[]

Функция xpath вычисляет выражение XPath 1.0 xpath (заданное в виде текста) для значения XML xml. Она возвращает массив значений XML, соответствующих набору узлов, созданному выражением XPath. Если выражение XPath возвращает скалярное значение, а не набор узлов, то возвращается массив из одного элемента.

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

Необязательный третий аргумент функции — это массив сопоставлений пространств имен. Этот массив должен быть двумерным массивом типа text с длиной второй оси, равной 2 (т.е. это должен быть массив массивов, каждый из которых состоит ровно из 2 элементов). Первый элемент каждой записи массива — это имя пространства имен (псевдоним), второй — его URI. Необязательно, чтобы предоставленные в этом массиве псевдонимы совпадали с используемыми в самом документе XML (другими словами, как в документе XML, так и в контексте функции xpath псевдонимы локальны).

Пример:

SELECT xpath('/my:a/text()', '<my:a xmlns:my="http://example.com">test</my:a>',
             ARRAY[ARRAY['my', 'http://example.com']]);

 xpath  
--------
 {test}
(1 row)

Чтобы работать с пространствами имен по умолчанию (анонимными), напишите что-то вроде этого:

SELECT xpath('//mydefns:b/text()', '<a xmlns="http://example.com"><b>test</b></a>',
             ARRAY[ARRAY['mydefns', 'http://example.com']]);

 xpath
--------
 {test}
(1 row)

xpath_exists

xpath_exists ( xpath text, xml xml [, массив_пространств_имен text[] ] ) → boolean

Функция xpath_exists является специализированной формой функции xpath. Вместо того чтобы возвращать отдельные значения XML, которые удовлетворяют выражению XPath 1.0, эта функция возвращает логическое значение, показывающее, был ли удовлетворен запрос или нет (в частности, было ли получено какое-либо значение, отличное от пустого набора узлов). Эта функция равнозначна предикату XMLEXISTS, за исключением того, что она также поддерживает аргумент сопоставления пространств имен.

Пример:

SELECT xpath_exists('/my:a/text()', '<my:a xmlns:my="http://example.com">test</my:a>',
                     ARRAY[ARRAY['my', 'http://example.com']]);

 xpath_exists  
--------------
 t
(1 row)

xmltable

XMLTABLE (
    [XMLNAMESPACES ( uri_пространства_имен AS имя_пространства_имен [, ...] ),]
    выражение_строки PASSING [BY {REF|VALUE}] выражение_документа [BY {REF|VALUE}]
    COLUMNS имя { тип [PATH выражение_столбца] [DEFAULT выражение_по_умолчанию] [NOT NULL | NULL]
                  | FOR ORDINALITY }
            [, ...]
) → setof record

Выражение xmltable создает таблицу на основе значения XML, фильтра XPath для извлечения строк и набора определений столбцов. Хотя синтаксически оно напоминает функцию, оно может присутствовать в запросе только в качестве таблицы в предложении FROM.

Необязательное предложение XMLNAMESPACES задает список разделенных запятыми пространств имен, где каждое uri_пространства_имен является выражением типа text, а каждое имя_пространства_имен — простой идентификатор. Оно определяет используемые в документе пространства имен XML и их псевдонимы. Специфицирование пространства имен по умолчанию в настоящее время не поддерживается.

Обязательный аргумент выражение_строки — это выражение XPath 1.0 (заданное в виде значения типа text), которое вычисляется с использованием в качестве элемента контекста переданного значения XML, для получения набора узлов XML. Эти узлы — то, что xmltable превращает в выходные строки. Если выражение_документа равно NULL или выражение_строки создает пустой набор узлов или любое значение, отличное от набора узлов, строки выдаваться не будут.

Аргумент выражение_документа предоставляет элемент контекста для аргумента выражение_строки. Этим элементом должен быть синтаксически корректный документ XML; фрагменты/леса не принимаются. Предложения BY REF и BY VALUE принимаются, но игнорируются (это рассматривается в подразделе Непреднамеренные ограничения реализации).

В стандарте SQL функция xmltable вычисляет выражения на языке XML Query, но QHB допускает только выражение XPath 1.0 (это рассматривается в подразделе Запросы ограничены XPath 1.0).

Обязательное предложение COLUMNS задает столбцы, которые будут созданы в выходной таблице. Его формат показан выше в шаблоне синтаксиса. Для каждого столбца необходимо задать имя и тип данных (если только не указано FOR ORDINALITY, что подразумевает тип integer). Предложения, задающие путь, значение по умолчанию и допустимость значений NULL, являются необязательными.

Столбец, помеченный FOR ORDINALITY, будет заполнен номерами строк, начиная с 1, в порядке узлов, полученных из результирующего набора узлов выражения_строки. Указанием FOR ORDINALITY можно пометить максимум один столбец.

Примечание
В XPath 1.0 не указывается порядок узлов в наборе, поэтому код, полагающийся на определенный порядок результатов, будет зависеть от реализации. Подробную информацию об этом см. в подразделе Ограничение XPath до версии 1.0.

Аргумент выражение_столбца для столбца — это выражение XPath 1.0, которое вычисляется для каждой строки, с использованием в качестве элемента контекста текущего узла из результата выражения_строки, чтобы найти значение этого столбца. Если выражение_столбца не задано, то в качестве неявного пути используется имя столбца.

Если выражение XPath столбца возвращает значение, отличное от XML (может быть только строкой, логическим значением или числовым значением двойной точности в XPath 1.0) и столбец имеет тип QHB, отличный от xml, значение этому столбцу будет присвоено так, как если бы типу QHB было присвоено строковое представление значения. (Если это логическое значение, его строковое представление принимается равным 1 или 0, если тип выходного столбца относится к числовой категории, и true или false в противном случае.)

Если выражение XPath столбца возвращает непустой набор узлов XML и этот столбец в QHB имеет тип xml, столбцу будет точно присвоен результат выражения, если он имеет форму документа или содержимого.1

Присвоенный выходному столбцу xml результат, отличный от XML, выдает содержимое, представляющее собой отдельный текстовый узел со строковым значением результата. Результат XML, назначенный столбцу любого другого типа, может содержать не более одного узла, или возникает ошибка. Если существует ровно один узел, значение этому столбцу будет присвоено так, как если бы типу QHB было присвоено строковое значение узла (как определено для функции string в XPath 1.0).

Строковое значение элемента XML представляет собой конкатенацию всех текстовых узлов, содержащихся в этом элементе и его потомках, в порядке следования этих узлов в документе. Строковым значением элемента без текстовых узлов-потомков является пустая строка (не NULL). Любые атрибуты xsi:nil игнорируются. Обратите внимание, что состоящий только из пробелов узел text() между двумя нетекстовыми элементами при этом сохраняется и начальные пробелы в узле text() не убираются. Правила, определяющие строковое значение других типов узлов XML и значений, отличный от XML, можно посмотреть в описании функции string в XPath 1.0.

Представленные здесь правила преобразования не совсем соответствуют стандарту SQL, как описано в подразделе Сопоставления типов данных и значений между SQL и XML.

Если выражение пути возвращает пустой набор узлов (обычно когда ему нет соответствия) для данной строки, столбцу будет присвоено значение NULL, если только не задано выражение_по_умолчанию — в таком случае используется значение, полученное в результате вычисления этого выражения.

Это выражение_по_умолчанию вычисляется не сразу же при вызове xmltable, а каждый раз, когда для столбца требуется значение по умолчанию. Если выражение квалифицируется как стабильное или неизменное, повторное вычисление может быть пропущено. Это означает, что в выражении_по_умолчанию можно с пользой использовать изменчивые функции, такие как nextval.

Столбцы могут быть помечены признаком NOT NULL. Если выражение_столбца для столбца NOT NULL ничему не соответствует и при этом отсутствует указание DEFAULT или результатом вычисления выражения_столбца тоже является NULL, выдается сообщение об ошибке.

Примеры:

CREATE TABLE xmldata AS SELECT
xml $$
<ROWS>
  <ROW id="1">
    <COUNTRY_ID>AU</COUNTRY_ID>
    <COUNTRY_NAME>Australia</COUNTRY_NAME>
  </ROW>
  <ROW id="5">
    <COUNTRY_ID>JP</COUNTRY_ID>
    <COUNTRY_NAME>Japan</COUNTRY_NAME>
    <PREMIER_NAME>Shinzo Abe</PREMIER_NAME>
    <SIZE unit="sq_mi">145935</SIZE>
  </ROW>
  <ROW id="6">
    <COUNTRY_ID>SG</COUNTRY_ID>
    <COUNTRY_NAME>Singapore</COUNTRY_NAME>
    <SIZE unit="sq_km">697</SIZE>
  </ROW>
</ROWS>
$$ AS data;

SELECT xmltable.*
  FROM xmldata,
       XMLTABLE('//ROWS/ROW'
                PASSING data
                COLUMNS id int PATH '@id',
                        ordinality FOR ORDINALITY,
                        "COUNTRY_NAME" text,
                        country_id text PATH 'COUNTRY_ID',
                        size_sq_km float PATH 'SIZE[@unit = "sq_km"]',
                        size_other text PATH
                             'concat(SIZE[@unit!="sq_km"], " ", SIZE[@unit!="sq_km"]/@unit)',
                        premier_name text PATH 'PREMIER_NAME' DEFAULT 'not specified') ;

 id | ordinality | COUNTRY_NAME | country_id | size_sq_km |  size_other  | premier_name  
----+------------+--------------+------------+------------+--------------+---------------
  1 |          1 | Australia    | AU         |            |              | not specified
  5 |          2 | Japan        | JP         |            | 145935 sq_mi | Shinzo Abe
  6 |          3 | Singapore    | SG         |        697 |              | not specified

В следующем примере показана конкатенация нескольких узлов text (), применение имени столбца в качестве фильтра XPath, а также обработка пробелов, комментариев XML и инструкций по обработке:

CREATE TABLE xmlelements AS SELECT
xml $$
  <root>
   <element>  Hello<!-- xyxxz -->2a2<?aaaaa?> <!--x-->  bbb<x>xxx</x>CC  </element>
  </root>
$$ AS data;

SELECT xmltable.*
  FROM xmlelements, XMLTABLE('/root' PASSING data COLUMNS element text);
         element         
-------------------------
   Hello2a2   bbbxxxCC  

Следующий пример иллюстрирует, как с помощью предложения XMLNAMESPACES можно задать список пространств имен, используемых в документе XML и в выражениях XPath:

WITH xmldata(data) AS (VALUES ('
<example xmlns="http://example.com/myns" xmlns:B="http://example.com/b">
 <item foo="1" B:bar="2"/>
 <item foo="3" B:bar="4"/>
 <item foo="4" B:bar="5"/>
</example>'::xml)
)
SELECT xmltable.*
  FROM XMLTABLE(XMLNAMESPACES('http://example.com/myns' AS x,
                              'http://example.com/b' AS "B"),
             '/x:example/x:item'
                PASSING (SELECT data FROM xmldata)
                COLUMNS foo int PATH '@foo',
                  bar int PATH '@B:bar');
 foo | bar
-----+-----
   1 |   2
   3 |   4
   4 |   5
(3 rows)


Отображение таблиц в XML

Следующие функции отображают содержимое реляционных таблиц в значения XML. Их можно рассматривать как средства экспорта в XML:

table_to_xml ( table regclass, nulls boolean,
               tableforest boolean, targetns text ) → xml
query_to_xml ( query text, nulls boolean,
               tableforest boolean, targetns text ) → xml
cursor_to_xml ( cursor refcursor, count integer, nulls boolean,
                tableforest boolean, targetns text ) → xml

Функция table_to_xml отображает содержимое именованной таблицы, передаваемой в параметр table. Тип regclass принимает строки, идентифицирующие таблицы, используя обычную запись, включая необязательное указание схемы и кавычки (подробную информацию см. в разделе Типы идентификаторов объектов). Функция query_to_xml выполняет запрос, текст которого передается в параметре query, и отображает набор результатов. Функция cursor_to_xml извлекает указанное количество строк из курсора, заданного параметром cursor. Этот вариант рекомендуется, если необходимо отобразить большие таблицы, поскольку каждой функцией создается в памяти результирующее значение.

Если параметр tableforest равен false, результирующий документ XML выглядит следующим образом:

<имя_таблицы>
  <row>
    <имя_столбца1>данные</имя_столбца1>
    <имя_столбца2>данные</имя_столбца2>
  </row>

  <row>
    ...
  </row>

  ...
</имя_таблицы>

Если же tableforest равен true, результатом является фрагмент содержимого XML, который выглядит следующим образом:

<имя_таблицы>
  <имя_столбца1>данные</имя_столбца1>
  <имя_столбца2>данные</имя_столбца2>
</имя_таблицы>

<имя_таблицы>
  ...
</имя_таблицы>

...

Если имя таблицы неизвестно, то есть при отображении запроса или курсора, то в первом формате используется строка table, а во втором — row.

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

Значения данных отображаются так же, как описано выше для функции xmlelement.

Параметр nulls определяет, нужно ли включать в выходные данные значения NULL. Если он равен true, значения NULL в столбцах представляются как:

<имя_столбца xsi:nil="true"/>

где xsi — префикс пространства имен для XML Schema Instance. Соответствующее объявление пространства имен будет добавлено к значению результата. Если он равен false, столбцы, содержащие значения NULL, просто не включаются в вывод.

Параметр targetns задает целевое пространство имен XML для результата. Если конкретное пространство имен не требуется, в этом параметре должна быть передана пустая строка.

Следующие функции возвращают документы XML Schema, описывающие отображения, выполняемые соответствующими функциями, описанными выше:

table_to_xmlschema ( table regclass, nulls boolean,
                     tableforest boolean, targetns text ) → xml
query_to_xmlschema ( query text, nulls boolean,
                     tableforest boolean, targetns text ) → xml
cursor_to_xmlschema ( cursor refcursor, nulls boolean,
                      tableforest boolean, targetns text ) → xml

Для получения соответствующих отображений данных XML и документов XML Schema важно, чтобы в этих функциях передавались одинаковые параметры.

Следующие функции выдают связанные вместе отображения данных XML и соответствующую XML Schema в одном документе (или лесу). Они могут быть полезны, когда требуются автономные и самоописываемые результаты:

table_to_xml_and_xmlschema ( table regclass, nulls boolean,
                             tableforest boolean, targetns text ) → xml
query_to_xml_and_xmlschema ( query text, nulls boolean,
                             tableforest boolean, targetns text ) → xml

Кроме того, имеются следующие функции для вывода аналогичных отображений целых схем или всей текущей базы данных:

schema_to_xml ( schema name, nulls boolean,
                tableforest boolean, targetns text ) → xml
schema_to_xmlschema ( schema name, nulls boolean,
                      tableforest boolean, targetns text ) → xml
schema_to_xml_and_xmlschema ( schema name, nulls boolean,
                              tableforest boolean, targetns text ) → xml

database_to_xml ( nulls boolean,
                  tableforest boolean, targetns text ) → xml
database_to_xmlschema ( nulls boolean,
                        tableforest boolean, targetns text ) → xml
database_to_xml_and_xmlschema ( nulls boolean,
                                tableforest boolean, targetns text ) → xml

Эти функции игнорируют таблицы, которые не может читать текущий пользователь. Функции уровня базы данных дополнительно игнорируют схемы, для которых у текущего пользователя нет права USAGE (использование).

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

Результат отображения содержимого схемы выглядит следующим образом:

<имя_схемы>

отображение-таблицы1

отображение-таблицы2

...

</имя_схемы>

где формат отображения таблицы зависит от параметра tableforest, описанного выше.

Результат отображения содержимого базы данных выглядит следующим образом:

<имя_бд>

<имя_схемы1>
  ...
</имя_схемы1>

<имя_схемы2>
  ...
</имя_схемы2>

...

</имя_бд>

где отображение схемы такое же, как указано выше.

В качестве примера использования выходных данных, создаваемых этими функциями, на Примере 1 показана таблица стилей XSLT, преобразующая выходные данные table_to_xml_and_xmlschema в документ HTML, содержащий табличное представление данных таблицы. Аналогичным образом результаты этих функций могут быть преобразованы в другие форматы на основе XML.

Пример 1. Таблица стилей XSLT для преобразования вывода SQL/XML в HTML

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns="http://www.w3.org/1999/xhtml"
>

  <xsl:output method="xml"
      doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
      doctype-public="-//W3C/DTD XHTML 1.0 Strict//EN"
      indent="yes"/>

  <xsl:template match="/*">
    <xsl:variable name="schema" select="//xsd:schema"/>
    <xsl:variable name="tabletypename"
                  select="$schema/xsd:element[@name=name(current())]/@type"/>
    <xsl:variable name="rowtypename"
                  select="$schema/xsd:complexType[@name=$tabletypename]/xsd:sequence/xsd:element[@name='row']/@type"/>

    <html>
      <head>
        <title><xsl:value-of select="name(current())"/></title>
      </head>
      <body>
        <table>
          <tr>
            <xsl:for-each select="$schema/xsd:complexType[@name=$rowtypename]/xsd:sequence/xsd:element/@name">
              <th><xsl:value-of select="."/></th>
            </xsl:for-each>
          </tr>

          <xsl:for-each select="row">
            <tr>
              <xsl:for-each select="*">
                <td><xsl:value-of select="."/></td>
              </xsl:for-each>
            </tr>
          </xsl:for-each>
        </table>
      </body>
    </html>
  </xsl:template>

</xsl:stylesheet>


Расширенные функции XML

Расширенные XML функции в QHB — это функции, представляющие дополнительные операции над данными, представленными в виде XML документов.

xml_append_child

xml_append_child ( XMLType_instance xml, XPath_string text, value_expr xml [, namespace_string text])

Функция xml_append_child добавляет введенное пользователем значение к целевому XML в качестве дочернего элемента узла, указанного выражением XPath.

В аргументе XMLType_instance передается экземпляр XMLType. В аргументе XPath_string передается выражение Xpath, указывающее один или несколько узлов, к которым должны быть присоединены один или несколько дочерних узлов. Можно указать абсолютную строку XPath_string с начальным слэшем или относительную строку XPath_string, опуская начальный слэш. Если опустить начальный слэш, контекст относительного пути по умолчанию соответствует корневому узлу. В аргументе value_expr передается один или несколько узлов XML. Он должен разрешаться в строку. Необязательный параметр namespace_string предоставляет информацию о пространстве имен для XPath_string. Этот параметр должен иметь тип text.

Пример:

select xml_append_child(
  '<body>
    <wow id="1">
      <lol/>
    </wow>
    <wow id="2">
      <lol/>
    </wow>
   </body>'::xml,
  '/body/wow/lol'::text,
  '<New>Append</New>'::xml
  )
;

Результат:

<body>
  <wow id="1">
    <lol>
      <New>Append</New>
    </lol>
  </wow>
  <wow id="2">
    <lol>
      <New>Append</New>
    </lol>
  </wow>
</body>

xml_insert_before

xml_insert_before ( XMLType_instance xml, XPath_string text, value_expr xml [, namespace_string text] )

Функция xml_insert_before вставляет введенное пользователем значение в целевой XML перед узлом, указанным выражением XPath. Эта функция похожа на xml_insert_after, но вставляет значение до, а не после целевого узла.

В аргументе XMLType_instance передается экземпляр XMLType. В аргументе XPath_string передается выражение Xpath, указывающее один или несколько узлов, в которые необходимо вставить один или несколько дочерних узлов. Можно указать абсолютную строку XPath_string с начальным слэшем или относительную строку XPath_string, опуская начальный слэш. Если опустить начальный слэш, контекст относительного пути по умолчанию соответствует корневому узлу. В аргументе value_expr передается фрагмент XML, определяющий один или несколько вставляемых узлов и их положение в родительском узле. Он должен разрешаться в строку. Необязательный параметр namespace_string предоставляет информацию о пространстве имен для XPath_string. Этот параметр должен иметь тип text.

Пример:

select xml_insert_before(
  '<body><wow id="1"><lol/></wow><wow id="2"><lol/></wow></body>'::xml,
  '/body/wow[2]'::text,
  '<wow id="BEFORE New one">WOOOW</wow>'::xml
  )
;

Результат:

<body>
  <wow id="1">
    <lol/>
  </wow>
  <wow id="BEFORE New one">WOOOW</wow>
  <wow id="2">
    <lol/>
  </wow>
</body>

xml_insert_after

xml_insert_after ( XMLType_instance xml, XPath_string text, value_expr xml [, namespace_string text] )

Функция xml_insert_after вставляет один или несколько узлов любого типа сразу после целевого узла, который не является узлом атрибута. Эта функция похожа на xml_insert_before, но вставляет после, а не до целевого узла.

В аргументе XMLType_instance передается целевой узел вставки. В аргументе XPath_string передается выражение XPath 1.0, которое находит в целевом узле ноль или более узлов любого типа, кроме узлов атрибутов. XML-данные вставляются сразу после каждого из этих узлов; то есть каждый указанный узел становится предшествующим одноуровневым узлом узла, указанного в value_expr. В аргументе value_expr передаются XML-данные, которые необходимо вставить. Можно указать один или несколько узлов любого типа. Порядок узлов сохраняется после вставки. В необязательном параметре namespace_string задается пространство имен для целевого узла.

Пример:

select xml_insert_after(
  '<body>
    <wow id="1">
     <lol/>
    </wow>
    <wow id="2">
     <lol/>
    </wow>
  </body>'::xml,
  '/body/wow[2]'::text,
  '<wow id="BEFORE new one">WOOOW</wow>'::xml
  )
;

Результат:

<body>
  <wow id="1">
    <lol/>
  </wow>
  <wow id="2">
    <lol/>
  </wow>
  <wow id="BEFORE new one">WOOOW</wow>
</body>

xml_insert_child_after

xml_insert_child_after ( XMLType_instance xml, XPath_string text, XPathChild_string text, value_expr xml [, namespace_string text] )

Функция xml_insert_child_after* вставляет один или несколько узлов любого типа сразу после целевого узла, который не является узлом атрибута. Документ XML, который является целью вставки, может быть основан на схеме или не основан на схеме.

В аргументе XMLType_instance передается целевой узел вставки. В аргументе XPath_string передается выражение XPath 1.0, которое находит в целевом узле ноль или более узлов любого типа, кроме узлов атрибутов. XML-данные вставляются в содержимое целевого узла, после узла, задаваемого выражением XPathChild_string. В аргументе XPathChild_string передается выражение XPath 1.0, которое находит в содержимом целевого узла ноль или более узлов, после которых будет вставлено значение value_expr. В аргументе value_expr передаются XML-данные, которые необходимо вставить. Можно указать один или несколько узлов любого типа. Порядок узлов сохраняется после вставки. В необязательном параметре namespace_string задается пространство имен для целевого и дочернего узла.

Пример:

select xml_insert_child_after(
  '<books xmlns=\"http://example.com/\">\
            <shelf>\
                <book>Book A</book>\
                <book>Book B</book>\
            </shelf>\
            <shelf>\
                <book>Book C</book>\
                <book>Book D</book>\
            </shelf>\
        </books>'::xml,
  '/books/shelf'::text,
  'book[2]'::text,
  '<book>Third book in a shelf</book>'::xml,
  'xmlns="http://example.com/"'::text
  )
;

Результат:

<books xmlns="http://example.com/">
  <shelf>
    <book>Book A</book>
    <book>Book B</book>
    <book>Third book in a shelf</book>
  </shelf>
  <shelf>
    <book>Book C</book>
    <book>Book D</book>
    <book>Third book in a shelf</book>
  </shelf>
</books>

xml_update

xml_update(XMLType_instance,Update_pair[],[, namespace_string ])

Функция xml_update принимает в качестве аргументов экземпляр XMLType и массив пар XPath-значение value_expr и возвращает экземпляр XMLType с обновленными значениями для каждой пары. Если XPath_string является элементом XML, то соответствующее value_expr должно быть экземпляром XMLType. Если XPath_string является атрибутом или текстовым узлом, то value_expr может быть любым скалярным типом данных. Можно указать абсолютную строку XPath_string с начальным слэшем или относительную строку XPath_string, опуская начальный слэш. Если опустить начальный слэш, контекст относительного пути по умолчанию соответствует корневому узлу.

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

Если обновить элемент XML до нуля, QHB удалит атрибуты и дочерние элементы элемента, и элемент станет пустым. Если обновить до нуля текстовый узел элемента, QHB удалит текстовое значение элемента, а сам элемент останется, но будет пустым.

Эта функция материализует XML-документ в памяти и обновляет значение. Для использования в операторе UPDATE для модификации содержимого в столбце таблицы необходимо использовать результат функции в выражении UPDATE ... SET.

Пример:

select xml_update(
  '
    <body>
     <wow id="1">WOW1</wow>
     <wow id="2">WOW2</wow>
     <foo id="1">FOO1</foo>
     <foo id="2">FOO2</foo>
    </body>'::xml,
  '{"/body/wow[1]","<NewNode>I am new</NewNode>","/body/foo[2]","<NewNode>Another new node</NewNode>"}'   
  )

Результат:

<body>
  <NewNode>I am new</NewNode>
  <wow id="2">WOW2</wow>
  <foo id="1">FOO1</foo>
  <NewNode>Another new node</NewNode>
</body>

xml_delete

xml_delete ( XMLType_instance, XPath_string [, namespace_string ])

Функция xml_delete удаляет узел или узлы, соответствующие выражению XPath, в целевом XML.

В аргументе XMLType_instance передается экземпляр XMLType. В аргументе XPath_string передается выражение Xpath, указывающее на один или несколько узлов, которые необходимо удалить. Можете указать абсолютную строку XPath_string с начальным слэшем или относительную строку XPath_string, опуская начальный слэш. Если опустить начальный слэш, контекст относительного пути по умолчанию соответствует корневому узлу. Любые дочерние узлы узлов, указанных в XPath_string, также удаляются. Необязательный параметр namespace_string предоставляет информацию о пространстве имен для XPath_string. Этот параметр должен иметь тип text.

Пример:

select xml_delete(
  '<body>
    <wow id="1">WOW1</wow>
    <wow id="2">WOW2</wow>
   </body>'::xml,
  '/body/wow[2]'::text   
  )
;

Результат:

<body>
  <wow id="1">WOW1</wow>
</body>

xml_extract_value

xml_ ( XMLType_instance, XPath_string [, namespace_string ])

Функция xml_extract_value возвращает скалярное значение, соответствующие выражению XPath в целевом XML; если выражению XPath соответствует несколько узлов, функция завершится с ошибкой.

В аргументе XMLType_instance передается экземпляр XMLType. В аргументе XPath_string передается выражение Xpath, указывающее на один или несколько узлов для поиска. Можно указать абсолютную строку XPath_string с начальным слэшем или относительную строку XPath_string, опуская начальный слэш. Если опустить начальный слэш, контекст относительного пути по умолчанию соответствует корневому узлу. Необязательный параметр namespace_string предоставляет информацию о пространстве имен для XPath_string. Этот параметр должен иметь тип text.

Пример:

select xml_extract_value(
  '<books>\
            <shelf>\
                <book>Book A</book>\
                <book>Book B</book>\
            </shelf>\
            <shelf>\
                <book>Book C</book>\
                <book>Book D</book>\
                <book>Book D</book>\
            </shelf>\
        </books>"'::xml,
  '/books/shelf/book[3]'::text
  )
;

Результат:

Book D   

xml_extract

xml_ ( XMLType_instance, XPath_string [, namespace_string ])

Функция xml_extract возвращает один или несколько узлов, соответствующих выражению XPath в целевом XML.

В аргументе XMLType_instance передается экземпляр XMLType. В аргументе XPath_string передается выражение Xpath, указывающее на один или несколько узлов, которые необходимо добавить в возвращаемый документ. Можно указать абсолютную строку XPath_string с начальным слэшем или относительную строку XPath_string, опуская начальный слэш. Если опустить начальный слэш, контекст относительного пути по умолчанию соответствует корневому узлу. Необязательный параметр namespace_string предоставляет информацию о пространстве имен для XPath_string. Этот параметр должен иметь тип text.

Пример:

select xml_extract(
  '<books>\
            <shelf>\
                <book>Book A</book>\
                <book>Book B</book>\
            </shelf>\
            <shelf>\
                <book>Book C</book>\
                <book>Book D</book>\
            </shelf>\
        </books>"'::xml,
  '/books/shelf/book'::text
  )
;

Результат:

<book>Book A</book>
<book>Book B</book>
<book>Book C</book>
<book>Book D</book>

xml_exists_node

xml_ ( XMLType_instance, XPath_string [, namespace_string ])

Функция xml_exists_node проверяет, существует ли узел или узлы, соответствующие выражению XPath в целевом XML; она возвращает 1, если хотя бы один узел найден, и 0 в противном случае.

В аргументе XMLType_instance передается экземпляр XMLType. В аргументе XPath_string передается выражение Xpath, указывающее на один или несколько узлов, которые необходимо удалить. Можно указать абсолютную строку XPath_string с начальным слэшем или относительную строку XPath_string, опуская начальный слэш. Если опустить начальный слэш, контекст относительного пути по умолчанию соответствует корневому узлу. Необязательный параметр namespace_string предоставляет информацию о пространстве имен для XPath_string. Этот параметр должен иметь тип text.

Пример:

select xml_exists_node(
  '<books>\
            <shelf>\
                <book1>Book A</book1>\
                <book2>Book B</book2>\
            </shelf>\
            <shelf>\
                <book1>Book C</book1>\
                <book2>Book D</book2>\
                <book3>Book D</book3>\
            </shelf>\
        </books>"'::xml,
  '/books/shelf/book3'::text
  )
;

Результат:

1

1

Примером формы содержимого является результат, содержащий более одного узла элемента на верхнем уровне или какой-либо непробельный текст вне единственного элемента. Результат XPath может иметь и другую форму, например, если это выражение возвращает узел атрибута, выбранный из содержащего этот атрибут элемента. Подобный результат будет приведен в форму содержимого, где каждый такой недопустимый узел заменяется его строковым значением, как определено для функции string в XPath 1.0.