xml2 — функциональность для выполнения запросов XPath и преобразований XSLT

Модуль xml2 предоставляет функционал для выполнения запросов XPath и преобразований XSLT.


Уведомление об исключении из числа рекомендованных

В QHB функциональность, связанная с XML, основана на стандарте SQL/XML и находится в ядре сервера. Эта функциональность охватывает проверку синтаксиса XML и запросы XPath, что как раз и делает этот модуль, но он имеет совершенно несовместимый API. Этот модуль планируется удалить в будущей версии QHB в пользу более нового стандартного API, поэтому мы рекомендуем вам попробовать перевести свои приложения на новый API.


Описание функций

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

xml_valid ( документ text ) → boolean

Разбирает переданный документ и возвращает true, если это правильно сформированный XML. (Примечание: это псевдоним стандартной функции QHB xml_is_well_formed(). Имя xml_valid() технически некорректно, поскольку понятия допустимости (valid) и правильности формата (well-formed) в XML имеют разное значение.)

xpath_string ( документ text, запрос text ) → text

Анализирует запрос XPath для предоставленного документа и приводит результат к типу text.

xpath_number ( документ text, запрос text ) → real

Анализирует запрос XPath для предоставленного документа и приводит результат к типу real.

xpath_bool ( документ text, запрос text ) → boolean

Анализирует запрос XPath для предоставленного документа и приводит результат к типу boolean.

xpath_nodeset ( документ text, запрос text, тег_верхнего_уровня text, тег_элемента text ) → text

Анализирует запрос для документа и обрамляет результат XML-тегами. Если результат содержит несколько значений, выходные данные будут выглядеть так:

<тег_верхнего_уровня>
<тег_элемента>Значение 1, которое может быть XML-фрагментом</тег_элемента>
<тег_элемента>Значение 2....</тег_элемента>
</тег_верхнего_уровня>

Если тег_верхнего_уровня или тег_элемента — пустая строка, соответствующий тег опускается.

xpath_nodeset ( документ text, запрос text, тег_элемента text ) → text

Подобна xpath_nodeset(документ, запрос, тег_верхнего_уровня, тег_элемента), но выводит результат без тега_верхнего_уровня.

xpath_nodeset ( документ text, запрос text ) → text

Подобна xpath_nodeset(документ, запрос, тег_верхнего_уровня, тег_элемента), но выводит результат без обоих тегов.

xpath_list ( документ text, запрос text, разделитель text ) → text

Анализирует запрос для документа и возвращает несколько значений, вставляя между ними заданный разделитель, например: Значение 1,Значение 2,Значение 3, если разделителем является знак «,».

xpath_list ( документ text, запрос text ) → text

Это обертка предыдущей функции, устанавливающая в качестве разделителя знак «,».


xpath_table

xpath_table(text key, text document, text relation, text xpaths, text criteria) returns setof record

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

Таблица 17. Параметры xpath_table

ПараметрОписание
keyимя «ключевого» поля — это просто поле, содержимым которого будет заполнен первый столбец выходной таблицы, т. е. оно указывает на запись, из которой была получена каждая выходная строка (см. примечание о нескольких значениях ниже)
documentимя поля, содержащего XML-документ
relationимя таблицы (или представления), содержащей документы
xpathsодно или несколько выражений XPath, разделенных символом |
criteriaсодержимое предложения WHERE. Этот параметр нельзя опустить, поэтому если хотите обработать все строки в отношении, напишите true или 1=1

Эти параметры (за исключением строк XPath) просто подставляются в обычный оператор SQL SELECT, так что у вас есть некоторая гибкость — оператор выглядит так:

SELECT <key>, <document> FROM <relation> WHERE <criteria>

поэтому в этих параметрах можно передать всё, что будет допустимо в этих позициях. Этот SELECT должен возвращать в результате ровно два столбца (что он и будет делать, если только вы не попытаетесь перечислить несколько полей для ключа или документа). Учтите, что при таком примитивном подходе вам обязательно нужно проверять все значения, получаемые от пользователя, во избежание атак с инъекцией SQL-кода.

Эта функция предназначена для использования в выражении FROM, с предложением AS, задающим выходные столбцы; например:

SELECT * FROM
xpath_table('article_id',
            'article_xml',
            'articles',
            '/article/author|/article/pages|/article/title',
            'date_entered > ''2003-01-01'' ')
AS t(article_id integer, author text, page_count integer, title text);

Предложение AS определяет имена и типы столбцов в выходной таблице. Первым идет «ключевое» поле, а за ним поля, соответствующие запросам XPath. Если запросов XPath больше, чем результирующих столбцов, лишние запросы будут игнорироваться. Если же результирующих столбцов больше, чем запросов XPath, лишние столбцы будут заполнены значением NULL.

Обратите внимание, что в этом примере результирующий столбец page_count определен как целочисленный. Эта функция внутри имеет дело со стоковыми представлениями, поэтому когда вы указываете, что в выходных данных хотите получить целое число, она берет строковое представление результата XPath и использует функции ввода QHB, чтобы преобразовать его в целое число (или в тип, указанный в предложении AS). Если она не сможет это сделать, произойдет ошибка — например, если результат пустой, — поэтому если вы считаете, что с данными могут возникнуть проблемы, возможно, стоит просто оставить для такого столбца тип text.

Вызывающий оператор SELECT необязательно должен быть простым SELECT * — он может обращаться к выходным столбцам по именам или соединять их с другими таблицами. Эта функция выдает виртуальную таблицу, с которой вы можете выполнять любые операции, какие пожелаете (например, агрегацию, соединение, сортировку данных и т. д.). Поэтому возможен и такой запрос:

SELECT t.title, p.fullname, p.email
FROM xpath_table('article_id', 'article_xml', 'articles',
                 '/article/title|/article/author/@id',
                 'xpath_string(article_xml,''/article/@date'') > ''2003-03-20'' ')
       AS t(article_id integer, title text, author_id integer),
     tblPeopleInfo AS p
WHERE t.author_id = p.person_id;

в качестве более сложного примера. Разумеется, для удобства весь этот запрос можно завернуть в представление.


Результаты с несколькими значениями

Функция xpath_table предполагает, что результаты каждого запроса XPath могут состоять из нескольких значений, поэтому количество возвращенных этой функцией строк может не совпадать с количеством входных документов. Первая возвращенная строка содержит первый результат каждого запроса, вторая — второй результат и т. д. Если один из запросов возвращает меньше значений, чем остальные, вместо недостающих значений будет возвращаться NULL.

В некоторых случаях пользователь будет знать, что данный запрос XPath возвратит только один результат (возможно, уникальный идентификатор документа), — если он используется одновременно с запросом XPath, возвращающим несколько результатов, результат с одним значением появится только в первой строке результата. Чтобы решить эту проблему, можно использовать ключевое поле для соединения результата с более простым запросом XPath. Например:

CREATE TABLE test (
    id int PRIMARY KEY,
    xml text
);

INSERT INTO test VALUES (1, '<doc num="C1">
<line num="L1"><a>1</a><b>2</b><c>3</c></line>
<line num="L2"><a>11</a><b>22</b><c>33</c></line>
</doc>');

INSERT INTO test VALUES (2, '<doc num="C2">
<line num="L1"><a>111</a><b>222</b><c>333</c></line>
<line num="L2"><a>111</a><b>222</b><c>333</c></line>
</doc>');

SELECT * FROM
  xpath_table('id','xml','test',
              '/doc/@num|/doc/line/@num|/doc/line/a|/doc/line/b|/doc/line/c',
              'true')
  AS t(id int, doc_num varchar(10), line_num varchar(10), val1 int, val2 int, val3 int)
WHERE id = 1 ORDER BY doc_num, line_num

 id | doc_num | line_num | val1 | val2 | val3
----+---------+----------+------+------+------
  1 | C1      | L1       |    1 |    2 |    3
  1 |         | L2       |   11 |   22 |   33

Чтобы получить doc_num в каждой строке, можно вызвать xpath_table дважды и соединить результаты:

SELECT t.*,i.doc_num FROM
  xpath_table('id', 'xml', 'test',
              '/doc/line/@num|/doc/line/a|/doc/line/b|/doc/line/c',
              'true')
    AS t(id int, line_num varchar(10), val1 int, val2 int, val3 int),
  xpath_table('id', 'xml', 'test', '/doc/@num', 'true')
    AS i(id int, doc_num varchar(10))
WHERE i.id=t.id AND i.id=1
ORDER BY doc_num, line_num;

 id | line_num | val1 | val2 | val3 | doc_num
----+----------+------+------+------+---------
  1 | L1       |    1 |    2 |    3 | C1
  1 | L2       |   11 |   22 |   33 | C1
(2 rows)

Функции XSLT

Если установлена libxslt, доступны следующие функции:

xslt_process

xslt_process(text document, text stylesheet, text paramlist) returns text

Эта функция применяет стилевое оформление XSL к документу и возвращает результат преобразования. Параметр paramlist — это список присваиваний значений параметрам, которые будут использоваться в преобразовании, заданных в форме a=1,b=2. Обратите внимание, что синтаксический анализ параметров очень прост: значения параметров не могут содержать запятые!

Также есть версия xslt_process с двумя параметрами, которая не передает преобразованию никаких параметров.


Автор

Джон Грей (John Gray), jgray@azuli.co.uk

Разработку этого модуля спонсировала компания Torchbox Ltd. (www.torchbox.com). Этот модуль выпускается под той же лицензией BSD, что и PostgreSQL.