xml2

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


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

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


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

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

Таблица 35. Функции xml2

Функция
Описание
xml_valid ( document text ) → boolean
Разбирает переданный документ и возвращает true, если это правильно сформированный XML. (Примечание: это псевдоним стандартной функции QHB xml_is_well_formed(). Имя xml_valid() технически некорректно, поскольку понятия допустимости (valid) и правильности формата (well-formed) в XML имеют разное значение.)
xpath_string ( document text, query text ) → text
Анализирует запрос XPath для предоставленного документа и приводит результат к типу text.
xpath_number ( document text, query text ) → real
Анализирует запрос XPath для предоставленного документа и приводит результат к типу real.
xpath_bool ( document text, query text ) → boolean
Анализирует запрос XPath для предоставленного документа и приводит результат к типу boolean.
xpath_nodeset ( document text, query text, toptag text, itemtag text ) → text
Анализирует запрос для документа и обрамляет результат XML-тегами. Если результат содержит несколько значений, выходные данные будут выглядеть так:
\
\Value 1 which could be an XML fragment\
\Value 2....\
\
Если toptag или itemtag — пустая строка, соответствующий тег опускается.
xpath_nodeset ( document text, query text, itemtag text ) → text
Подобна xpath_nodeset(document, query, toptag, itemtag), но выводит результат без toptag.
xpath_nodeset ( document text, query text ) → text
Подобна xpath_nodeset(document, query, toptag, itemtag), но выводит результат без обоих тегов.
xpath_list ( document text, query text, separator text ) → text
Анализирует запрос для документа и возвращает несколько значений, вставляя между ними заданный разделитель, например: Значение 1,Значение 2,Значение 3, если separator равен знаку «,».
xpath_list ( document text, query text ) → text
Это обертка предыдущей функции, устанавливающая в качестве разделителя знак «,».

xpath_table

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

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

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

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

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

SELECT <ключ>, <документ> FROM <отношение> WHERE <критерий>

поэтому в этих параметрах можно передать всё, что будет допустимо в этих позициях. Этот 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.