D.3. Ограничения XML и совместимость с SQL/XML #
В SQL:2006 были внесены значительные изменения в посвящённой XML части ISO/IEC 9075-14 (SQL/XML). Реализация типа данных XML и связанных функций в PostgreSQL в большей степени соответствует более ранней редакции, SQL:2003, с некоторыми заимствованиями из последующих редакций. В частности:
Тогда как в текущем стандарте существует семейство типов данных XML, содержащих «документы» или «содержимое» в нетипизированном виде или с типами XML Schema, а также тип
XML(SEQUENCE)
, содержащий произвольные части XML-документа, в PostgreSQL есть только один типxml
, который может содержать «документ» или «содержимое». Определённый в стандарте тип «последовательность» в PostgreSQL отсутствует.PostgreSQL предоставляет две функции, появившиеся в SQL:2006, но вместо языка XML Query, как должно быть согласно стандарту, в них используется язык XPath 1.0.
PostgreSQL не поддерживает предложения
RETURNING CONTENT
иRETURNING SEQUENCE
: реализация функций, определяемых с этими предложениями в спецификации, подразумевает возврат содержимого.
В этом разделе описаны некоторые из образовавшихся в итоге различий, с которыми вы можете столкнуться.
D.3.1. Запросы ограничиваются XPath версии 1.0 #
Специфичные для PostgreSQL функции xpath()
и xpath_exists()
выполняют запросы к XML-документам на языке XPath. В PostgreSQL также имеются поддерживающие только XPath стандартные функции XMLEXISTS
и XMLTABLE
, хотя согласно стандарту они должны поддерживать XQuery. Все эти функции в PostgreSQL реализованы с использованием библиотеки libxml2, которая поддерживает только XPath 1.0.
Существует тесная связь между языком XQuery и XPath версии 2.0 и новее: любое выражение, синтаксически правильное и выполняющееся успешно, выдаёт в обоих языках одинаковые результаты (за незначительным исключением, связанным с числовым обозначением символов или использованием предопределённых сущностей — XQuery заменяет их соответствующими символами, а XPath оставляет в исходном виде). Но между XPath 1.0 и этими языками подобная связь отсутствует: он появился гораздо раньше и во многом отличается от них.
Заслуживают отдельного рассмотрения две категории ограничений: ограничение языка XQuery до XPath для функций, описанных в стандарте SQL, и ограничение XPath до версии 1.0 как для стандартизированных функций, так и для специфичных функций PostgreSQL.
D.3.1.1. Ограничение языка XQuery до XPath #
В число отличий XQuery от XPath входят:
Выражения XQuery могут выдавать не только всевозможные значения XPath, но и конструировать новые XML-узлы. XPath может создавать и возвращать значения атомарных типов (числа, строки и так далее), но выдаваемые им XML-узлы должны уже присутствовать в документе, поступившем на вход выражения.
В XQuery есть управляющие конструкции для организации циклов, сортировки и группировки.
В XQuery поддерживается объявление и использование локальных функций.
В последних версиях XPath начинают появляться возможности, пересекающиеся с имеющимися в XQuery (например, конструкции for-each
, sort
, анонимные функции и функция parse-xml
, создающая узел из строки), но до XPath 3.0 их не было.
D.3.1.2. Ограничения XPath до версии 1.0 #
Разработчикам, знакомым с XQuery и XPath 2.0 или новее, приходится иметь дело с рядом недостатков XPath версии 1.0:
Фундаментальный тип результатов XQuery/XPath, тип
sequence
, который может содержать XML-узлы, атомарные значения, и всё это вместе, в XPath 1.0 отсутствует. В 1.0 выражения могут выдавать только набор узлов (состоящих из нуля или нескольких узлов XML) или единственное атомарное значение.В отличие от последовательностей XQuery/XPath, которые могут содержать произвольные элементы в любом требующемся порядке, во множестве узлов XPath 1.0 нет гарантированного порядка, и оно, как и любое другое множество, не может содержать несколько вхождений одного элемента.
Примечание
Библиотека libxml2 не всегда возвращает в PostgreSQL наборы узлов с внутренними членами в том порядке, в котором они идут во входном документе. В её документации не гарантируется корректное поведение, а выражение XPath 1.0 не может на это воздействовать.
Тогда как XQuery/XPath поддерживают все типы, определённые в стандарте XML Schema, а также множество операторов и функций, работающих с этими типами, XPath 1.0 поддерживает только множества узлов и три атомарных типа:
boolean
,double
иstring
.В XPath 1.0 отсутствует условный оператор. Выражение XQuery/XPath вида
if ( hat ) then hat/@size else "no hat"
не имеет эквивалента в XPath 1.0.В XPath 1.0 нет оператора сравнения строк с упорядочиванием. Условия
"cat" < "dog"
и"cat" > "dog"
оба являются ложными, так как они выполняются как числовые сравнения двух значенийNaN
. Условия же=
и!=
, напротив, сравнивают строки в виде строк.XPath 1.0 размывает разницу между сравнением значений и общими сравнениями, которая имеется в XQuery/XPath. Сравнения
sale/@hatsize = 7
иsale/@customer = "alice"
по сути являются количественными сравнениями, и результатом их будет истина, если существует элементsale
с заданным значением атрибута, тогда какsale/@taxable = false()
— сравнение всего набора узлов с фактическим логическим значением. Его результат будет истиной, только если у элементаsale
вовсе не будет атрибутаtaxable
.В модели данных XQuery/XPath узел документа может иметь либо форму документа (то есть содержать в точности один элемент верхнего уровня, снаружи которого допускаются только комментарии и инструкции обработки), либо форму содержимого (с ослабленными ограничениями). В XPath 1.0 ему соответствует корневой узел, который может иметь только форму документа. Этим отчасти объясняется то, что значение типа
xml
, передаваемое в качестве элемента контекста любым функциям PostgreSQL на базе XPath, должно быть в форме документа.
Кроме отмеченных выше имеются и другие различия. В языках XQuery и XPath версии 2.0 и новее существует режим совместимости с XPath 1.0, а в документации W3C имеется перечень изменений функций и изменений в языке применительно к этому режиму. Этот перечень гораздо более полный, но тоже не исчерпывающий. Даже режим совместимости этих языков не обеспечивает их полную идентичность XPath 1.0.
D.3.1.3. Преобразование значений/типов данных между SQL и XML #
В SQL:2006 и более поздних ревизиях чётко определены преобразования между стандартными типами SQL и типами стандарта XML Schema в обе стороны. Однако эти правила выражаются в типах и понятиях, определённых в XQuery/XPath, и не могут быть непосредственно применены к другой модели данных, присущей XPath 1.0.
Когда PostgreSQL сопоставляет значения данных SQL с XML (как в функции xmlelement
), или XML с SQL (как в выходных столбцах xmltable
), за исключением нескольких отдельно обрабатываемых случаев, PostgreSQL просто полагает, что строка XPath 1.0, содержащая данные типа XML, будет допустимой для ввода в текстовом виде в тип данных SQL, и наоборот. Это правило добродетельно своей простотой, и при этом преобразования для многих типов данных в итоге оказываются такими, какими и должны быть согласно стандарту.
Там же, где это нужно для взаимодействия с другими системами, для некоторых типов данных можно явно использовать функции форматирования типов данных (например, описанные в Разделе 9.8) для получения преобразований, в точности соответствующих стандарту.
D.3.2. Непреднамеренные ограничения реализации #
В этом разделе описываются дополнительные ограничения, присущие текущей реализации в PostgreSQL, но не самой библиотеке libxml2.
D.3.2.1. Передача параметров только по значению (BY VALUE
) #
В стандарте SQL определены два механизма передачи параметров, осуществляющих передачу XML-аргумента из SQL в XML-функцию или получение результата: BY REF
, в котором конкретное значение в XML остаётся привязанным к своему узлу, и BY VALUE
, в котором передаётся содержимое XML, но связь с узлом теряется. Выбрать механизм можно перед списком параметров, в качестве механизма по умолчанию для всех параметров, или после каждого отдельного параметра, переопределив тем самым выбор по умолчанию.
В качестве иллюстрации различия взгляните на следующие два запроса, которые в окружении SQL:2006 выдают true и false, если x
является XML-значением:
SELECT XMLQUERY('$a is $b' PASSING BY REFx
AS a,x
AS b NULL ON EMPTY); SELECT XMLQUERY('$a is $b' PASSING BY VALUEx
AS a,x
AS b NULL ON EMPTY);
PostgreSQL принимает указания BY VALUE
и BY REF
в конструкции XMLEXISTS
или XMLTABLE
, но игнорирует их. Тип xml
содержит сериализованное представление данных в текстовом виде, поэтому сущность узла, которую нужно сохранять, отсутствует, и передача фактически производится по значению (BY VALUE
).
D.3.2.2. Отсутствие именованных параметров запросов #
Функции на базе XPath могут принимать один параметр, служащий контекстным элементом для выражения XPath, но не поддерживают передачу дополнительных значений, которые могли бы использоваться в выражении как именованные параметры.
D.3.2.3. Отсутствие типа XML(SEQUENCE)
#
Тип данных xml
в PostgreSQL может содержать значение только в форме документа (DOCUMENT
) или содержимого (CONTENT
). Контекстный элемент выражения XQuery/XPath должен быть одиночным XML-узлом или атомарным значением, но в XPath 1.0 это может быть только XML-узел, и при этом нет типа узла, содержащего CONTENT
. Как следствие, в PostgreSQL в качестве контекстного элемента XPath можно передать данные XML в единственном виде — в виде правильно оформленного документа (DOCUMENT
).