Ограничения XML и совместимость с SQL/XML#

Примечание

Эта страница переведена при помощи нейросети GigaChat.

Значительные изменения спецификаций, связанных с XML, были внесены в ISO/IEC 9075-14 (SQL/XML) с выходом стандарта SQL:2006. Реализация PostgreSQL типа данных XML и соответствующих функций в основном следует более раннему изданию от 2003 года, заимствуя некоторые элементы из последующих изданий. В частности:

  • Вместо того чтобы предоставлять семейство типов данных XML для хранения «документов» или «содержимого», типизированных либо нетипизированных по схеме XML-схемы, а также отдельного типа XML(SEQUENCE) для произвольного содержимого XML, PostgreSQL предоставляет единый тип xml, который может хранить «документы» или «содержимое». Эквивалента стандартного типа «последовательность» здесь нет.

  • PostgreSQL реализует две функции, введенные в стандарте SQL:2006, но использует их варианты, основанные на языке XPath 1.0 вместо языка запросов к XML, указанного в стандарте.

  • PostgreSQL не поддерживает предложения RETURNING CONTENT и RETURNING SEQUENCE, функции, определенные со ссылками на них в спецификации, возвращают содержимое неявно.

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

Запросы ограничиваются языком XPath версии 1.0#

Функции PostgreSQL, специфичные для работы с типом данных XML, xpath() и xpath_exists(), используют язык XPath для выполнения запросов к документам XML. Кроме того, PostgreSQL предлагает только те варианты стандартных функций XMLEXISTS и XMLTABLE, которые официально должны использовать язык XQuery, но фактически работают исключительно с XPath. Для всех этих функций PostgreSQL полагается на библиотеку libxml2, которая поддерживает только версию XPath 1.0.

Между языками XQuery и версиями XPath начиная с 2.0 существует тесная связь: любое выражение, синтаксически корректное и успешно выполняемое в обоих языках, дает одинаковый результат (за исключением незначительных случаев выражений, содержащих числовые ссылки на символы или предопределенные сущности, которые заменяются соответствующим символом в XQuery, тогда как в XPath они остаются неизменными). Однако такой связи между этими языками и версией XPath 1.0 нет; это был более ранний язык, отличающийся во многих аспектах.

Следует учитывать два вида ограничений: ограничение перехода от XQuery к XPath для функций, указанных в стандарте SQL, и ограничение использования XPath до версии 1.0 как для стандартных функций, так и для функций, специфичных для PostgreSQL.

Переход от XQuery к XPath#

По сравнению с XPath возможности языка XQuery включают следующие особенности:

  • Выражения XQuery могут создавать и возвращать новые узлы XML помимо любых возможных значений XPath. XPath может генерировать и возвращать значения атомарных типов (числа, строки и др.), но он способен вернуть лишь те узлы XML, которые уже присутствовали в документах, предоставленных на вход выражения.

  • XQuery имеет управляющие конструкции для итерации, сортировки и группировки.

  • XQuery позволяет объявлять и использовать локальные функции.

Последние версии XPath начинают предлагать аналогичные возможности (например, функциональные стили for-each и sort, анонимные функции и parse-xml для создания узла из строки), однако таких возможностей не было до выхода XPath 3.0.

Использование 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 всегда возвращает наборы узлов в том же относительном порядке, в котором они находились в исходном документе, хотя документация библиотеки не гарантирует такого поведения, и выражение XPath 1.0 не может его контролировать.

  • Хотя XQuery/XPath предоставляют все типы, определенные в XML-схеме, множество операторов и функций над ними, 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, передаваемое в качестве контекстного элемента любой основанной на XPath функции PostgreSQL, обязательно должно находиться в форме документа.

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

Соответствие между типами и значениями данных SQL и XML#

В стандарте SQL:2006 и более поздних версиях обе стороны преобразования между стандартными типами данных SQL и типами схем XML специфицированы четко. Однако правила выражаются с использованием типов и семантики языка XQuery/XPath и напрямую неприменимы к другой модели данных XPath 1.0.

Когда PostgreSQL отображает значения данных SQL в XML (например, в xmlelement), или из XML в SQL (например, в выходных столбцах xmltable), за исключением нескольких специально обработанных случаев, PostgreSQL просто предполагает, что строковая форма типа данных XML по XPath 1.0 будет действительна в качестве текстовой формы ввода для соответствующего типа данных SQL, и наоборот. Это правило обладает достоинством простоты при получении результатов, аналогичных тем, которые указаны в стандарте, для многих типов данных.

Если важна совместимость с другими системами, для некоторых типов данных может потребоваться явно использовать функции форматирования типов данных, чтобы получить стандартные сопоставления.

Случайные ограничения реализации#

Этот раздел касается ограничений, которые не присущи библиотеке libxml2, но применимы к текущей реализации в PostgreSQL.

Поддерживается только механизм передачи BY VALUE#

Стандарт SQL определяет два механизма передачи передач, которые применяются при передаче аргумента XML от SQL к XML-функции или приеме результата: BY REF, при котором конкретное значение XML сохраняет свою идентичность узла, и BY VALUE, при котором передается содержимое XML, но идентичность узла не сохраняется. Механизм можно указать перед списком параметров в качестве механизма по умолчанию для всех них или после любого параметра для переопределения по умолчанию.

Чтобы проиллюстрировать разницу, если x является значением XML, следующие два запроса в среде SQL:2006 дадут результаты true и false, соответственно:

SELECT XMLQUERY('$a is $b' PASSING BY REF x AS a, x AS b NULL ON EMPTY);
SELECT XMLQUERY('$a is $b' PASSING BY VALUE x AS a, x AS b NULL ON EMPTY);

PostgreSQL примет BY VALUE или BY REF в конструкции XMLEXISTS или XMLTABLE, но игнорирует их. Тип данных xml хранит сериализованное представление в виде символьной строки, поэтому нет никакой идентичности узлов, которую нужно было бы сохранить, а передача всегда фактически осуществляется посредством BY VALUE.

Невозможно передать именованные параметры запросам#

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

Нет типа XML(SEQUENCE)#

Тип данных PostgreSQL xml может хранить значение только в форме DOCUMENT или CONTENT. Контекстный элемент выражения XQuery/XPath должен быть единственным узлом XML или атомарным значением, однако XPath 1.0 дополнительно ограничивает его до единственного узла XML и не имеет типа узла, допускающего CONTENT. В результате хорошо сформированное DOCUMENT – это единственная форма значения XML, которое PostgreSQL может предоставить в качестве контекстного элемента XPath.