Перейти к тексту

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

При первом входе в developerWorks для Вас будет создан профиль. Выберите информацию отображаемую в Вашем профиле — скрыть или отобразить поля можно в любой момент.

Вся введенная информация защищена.

  • Закрыть [x]

При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

Вся введенная информация защищена.

  • Закрыть [x]

Генерирование XML из IDS 9.x

Жак Рой, специалист по поддержке продаж, IBM
Jacques Roy photo
Жак Рой (Jacques Roy) Жак Рой является сотрудником всемирной организации поддержки продаж продуктов фирмы IBM. Он имеет более чем двадцатилетний стаж работы и уже более пяти лет занимается расширяемостью баз данных. Он является автором книги "Informix Dynamic Server 2000: Серверное программирование на языке C" и соавтором книги "Компоненты с открытым исходным кодом для Informix Dynamic Server 9.x".

Описание:  В данной статье рассматривается использование расширяемости IBM Informix® Dynamic Server для генерирования данных в XML-формате. Приводится пример исходного кода.

Дата:  25.02.2003
Уровень сложности:  средний
Активность:  3101 просмотров
Комментарии:  


Введение

XML становится все более и более важным для предприятий. Часто пользователям нужно создавать XML-документы из содержимого реляционной базы данных. Это можно сделать разными способами, но функции расширяемости IBM® Informix Dynamic Server® version 9.x (IDS 9.x) предоставляют возможность создавать свои собственные функции для генерирования XML из вашей базы данных.

В данной статье рассматривается простой подход к генерированию XML, который может соответствовать многим требованиям и предоставить стандартный блок для более сложных решений. Пример, сопровождающий эту статью, использует демонстрационную базу данных stores7, поставляемую вместе с продуктом IDS 9.x.


Стандартный блок

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

IDS 9.x предоставляет поддержку для нового типа с названием rows. Это означает, что результаты целой строки могут быть переданы в определенную пользователем функцию (user-defined function - UDF) как один аргумент. Строка определяется столбцами, имеющими имя и тип. Что остается сделать – передать дополнительный аргумент, идентифицирующий имя строки для инкапсулирования данных строки в XML-представлении. Рассмотрим функцию, имеющую следующее определение:

CREATE FUNCTION genxml(varchar(30), ROW)
RETURNING lvarchar
. . .

Первый аргумент – это имя, которое мы хотим дать строке, а второй аргумент – это сама строка. Строка содержит свое определение, то есть, функция genxml может определить количество столбцов в строке, их имена и т.д. Следующие команды генерируют XML-представление для каждой строки таблицы customer:

SELECT genxml("customer", customer)
FROM customer;

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

<customer>
<customer_num>101&lt//customer_num>
<fname>Ludwig        </fname>
<lname>Pauli         </lname>
<company>All Sports Supplies </company>
<address1>213 Erstwild Court  </address1>
<city>Sunnyvale      </city>
<state>CA</state>
<zipcode>94086</zipcode>
<phone>408-789-8075      </phone>
</customer>

Имена столбцов были извлечены из определения строки функцией genxml и использованы как теги для соответствующих столбцов. Но что, если мы хотим не весь список столбцов? Мы можем динамически создать строку с желаемыми столбцами как второй аргумент функции genxml следующим образом:

SELECT genxml("customer", ROW(customer_num, fname, lname))
FROM customer;

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

SELECT genxml("customer_calls",
        ROW(A.customer_num, fname, lname, call_dtime, call_code,
            call_descr, res_dtime, res_dtime, res_descr)
       )
FROM customer a, cust_calls b
WHERE a.customer_num = b.customer_num;

Эти примеры иллюстрируют множество требований по генерированию строк в XML-формате. Также может существовать требование сгенерировать XML-файл на основе результатов SQL-команды, содержащей агрегатное выражение. Агрегатные выражения можно передавать в функцию genxml, как показано ниже:

SELECT genxml("stats", ROW(customer_num, COUNT(*)) )
FROM cust_calls
GROUP BY customer_num;

Теперь с этим основным инструментом мы готовы завершить создание XML-документа, добавив заголовок и сноску.


Обработка значений NULL

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


Обработка типа row

Таблица может содержать столбец, имеющий тип row. В этом случае переданная в функцию genxml строка будет содержать именованный или неименованный тип row. Например, мы могли бы иметь следующее определение:

CREATE ROW TYPE address_t (
  name     varchar(20),
  address1 varchar(20),
  address2 varchar(20),
  city     varchar(15),
  state    char(2),
  zipcode  char(5)
);
CREATE TABLE employee (
  name varchar(30),
  address  address_t,
  phone  varchar(18)
);

Функция будет обрабатывать тип row, именованный или неименованный, так же как и другие базовые типы. Выполнение и результат запроса по таблице employee выглядел бы так:

SELECT genxml("employee", employee) FROM employee;

<employee>
<name>Roy</name>
<address>
  <address1>123 first street</address1>
  <city>Denver</city>
  <state>CO</state>
  <zipcode>80111</zipcode>
</address>
<phone>303-555-1212</phone>
</employee>

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


Иерархии таблиц

Есть еще одна ситуация, которую мы должны рассмотреть. IDS 9.x поддерживает определение иерархий таблиц, основанных на именованных типах row. На рисунке 1 показан пример иерархии.


Рисунок 1. Пример иерархии
Рисунок 1. Пример иерархии

Одной из причин наличия такой иерархии является возможность выполнять вычисления рисков, отличающихся в зависимости от типов ссуд. Создав несколько функций risk, работающих с конкретными типами row, мы можем выполнить следующий запрос:

SELECT loan_number, risk(loans) FROM loans WHERE branch_id = 127;

Этот запрос перебирает все строки с branch_id равным 127 и вызывает соответствующую функцию risk в зависимости от типа возвращаемой строки. Если мы хотим сгенерировать XML-представление для каждого типа loan для конкретной отрасли (branch) с использованием существующей функции genxml, мы должны выполнить один SQL-запрос для каждой подчиненной таблицы. Мы должны сделать это для того, чтобы дать для каждой строки нужное имя типа row.

Поскольку мы работаем с именованными типами row, функция genxml могла бы извлекать эту информацию и использовать ее неявно. Обратите внимание, что IDS различает функции в зависимости от их названий и типов аргументов. Следовательно, мы можем создать новую, дополнительную функцию genxml, принимающую в качестве аргумента только строку и извлекающую имя из определения строки. Затем мы можем сгенерировать XML-представление таблицы loans для конкретной отрасли при помощи следующей SQL-команды:

SELECT genxml(loans) FROM loans WHERE branch_id = 127;

Если бы вы использовали эту функцию с неименованным типом row, заголовком было бы полное определение строки. Для таблицы customer вы получили бы следующий заголовок:

<ROW(customer_num integer, fname char(15), lname char(15),
     company char(20), address1 char(20), address2 char(20),
     city char(15),state char(2), zipcode char(5),
     phone char(18)
    )>

Аналогичное имя строки использовалось бы и для закрывающего тега строки.


Завершение XML-документа

XML используется для описания данных. Он может включать в себя также информацию, указывающую тип документа и определения корректных документов этого типа. Такие файлы называются декларациями типа документа (document type declaration -DTD). DTD сами являются XML-документами.

XML описывает данные, но не способ их представления. Представление информации может быть описано на расширяемом языке таблиц стилей (extensible stylesheet language - XSL).

Наконец, вы должны указать, что документ является XML-документом и соответствует конкретному XML-стандарту. Это значит, что вы должны окружить сгенерированные строки, по крайней мере, указанием, что это XML-документ, и тегом для завершения документа. Результат может быть примерно таким:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE customer_set SYSTEM "/home/dtd/customer_set.dtd">
<?xml-stylesheet type="text/xsl"
                 href="/home/xsl/customer_set.xsl" ?>
<customer_set>
. . . (XML-formatted rows)
</customer_set>

CREATE PROCEDURE xmlcustomerset()
RETURNING LVARCHAR
  DEFINE result LVARCHAR;
  DEFINE ressql LVARCHAR;
  LET result = '<?xml version="1.0" encoding="ISO-8859-1" ?>';
  LET result = result ||
      '<!DOCTYPE customer_set SYSTEM "/home/dtd/customer_set.dtd">';
  LET result = result ||
'<?xml-stylesheet type="text/xsl" href="/home/xsl/customer_set.xsl" ?>';
  LET result = result || '<customer_set>';
  FOREACH SELECT genxml('customer', customer) INTO ressql FROM customer
    LET result = result || ressql;
  END FOREACH;
  LET result = result || '</customer_set>';
  RETURN result;
END PROCEDURE;
EXECUTE PROCEDURE xmlcustomerset();

Процедура очень простая. Она просто инициализирует переменную result заголовочной информацией. Затем выполняет SQL-команды, возвращающие несколько строк в XML-формате, и добавляет результат к переменной result. Наконец, она завершает документ, добавляя закрывающий тег customer_set, и возвращает результат. Последняя строка показывает, как выполняется процедура.


Отслеживание заголовочной информации

Процесс создания XML-документа из хранимой процедуры всегда один и тот же. Хорошо бы было обобщить процесс вместо создания множества хранимых процедур. Первым шагом для этого является поиск способа отслеживания типа документа и таблицы стилей, которые будут использоваться. Мы можем использовать таблицу для хранения этой информации:

CREATE TABLE genxmlinfo (
  name       varchar(30) PRIMARY KEY,
  dtypepath  lvarchar,
  xslpath    lvarchar
);

Столбец name – это тип используемого документа. В приведенном выше примере это customer_set. Столбец dtypepath содержит путь к DTD, а xslpath содержит путь к XSL, используемой для данного типа. Если значение столбца равно NULL, строка заголовка не появляется в документе. Это дает нам гибкость в определении того, что должно включаться в документ.


Обобщение создания XML-документов

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

Теперь, когда у нас есть способ извлекать информацию о заголовке, мы можем создать дополнительные пользовательские функции, которые будут выполнять SQL-команды динамически и добавлять информацию о заголовке. Мы можем решить эту задачу двумя способами. Либо мы просто работаем с результатом функции genxml(), либо мы принимаем общую SQL-команду и форматируем строки, возвращаемые командой. Сначала рассмотрим последний вариант.

Мы должны разработать функцию, принимающую в качестве аргументов тип документа и SQL-команду, и возвращающую полный XML-документ:

CREATE FUNCTION genxmlhdr(LVARCHAR, LVARCHAR)
RETURNING LVARCHAR
. . .

Затем мы можем сгенерировать XML-документ customer_set, выполнив следующую команду:

EXECUTE FUNCTION genxmlhdr("customer_set",
                           "SELECT * FROM customer");

При этом сгенерируется XML-документ, который немного отличается от XML-документа, сгенерированного процедурой xmlcustomerset(): у нас нет способа предоставить имя для возвращаемых строк. Мы должны дать им общее имя. В данном случае - row. Это не является проблемой. Мы просто должны принимать это во внимание при сопоставлении DTD и XSL-документов, относящихся к нашим типам документов.

Мы можем обеспечить немного большую гибкость, добавив функцию, аналогичную genxml(lvarchar, lvarchar), предполагающую, что результатом SQL-команды будут строки в XML-формате. Команда для создания документа customer_set станет такой:

EXECUTE FUNCTION addxmlhdr("customer_set",
        "SELECT genxml('customer', customer) FROM customer");

Для завершения нашего набора функций мы должны добавить еще одну функцию, принимающую SQL-команду и возвращающую все строки XML-документа без информации о заголовке. С этой функцией теперь возможно выполнять динамические SQL-команды в хранимой процедуре. Поскольку сигнатура этой функции отличается от сигнатуры genxml(lvarchar, row), мы можем использовать это же имя:

CREATE FUNCTION genxml(LVARCHAR, LVARCHAR)
RETURNING LVARCHAR
. . .

Первый аргумент представляет имя строки, а второй – SQL-команду. Команда для генерирования документа customer_set без заголовка следующая:

EXECUTE FUNCTION genxml("customer_set", "SELECT * FROM customer");


Пользовательские агрегатные функции

IDS 9.x предоставляет возможность создавать собственные агрегатные функции. Поскольку создание XML-документа включает в себя обработку набора строк для возврата одного результата, пользовательские агрегатные функции (user-defined aggregate - UDA) хорошо подходят для XML-обработки.

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

Если порядок строк не важен, вы могли бы сгенерировать XML-документ, используя UDA. Этот UDA должен использоваться следующим способом:

SELECT aggrxml(customer, "customer_set") FROM customer;

Первый аргумент UDA – строка, которую мы хотим обработать. Второй аргумент – значение, представляющее название типа генерируемого документа. Это значит, что результат будет аналогичен результату, генерируемому функциями genxml(lvarchar, lvarchar), которые рассматривались выше. Такое применение более естественно, чем использование команды EXECUTE FUNCTION. Поскольку это агрегатная функция, вы можете воспользоваться преимуществами SQL-предложения GROUP BY. Эта возможность полезна при генерировании нескольких XML-документов. Например, она может уменьшить количество SQL-команд, выполняемых в хранимой процедуре, путем удаления встроенного цикла FOR EACH.


Реализация

Все рассмотренные выше функции были реализованы на языке C и доступны в примере кода. Вот список функций, включая типы их аргументов:

addxmlhdr(lvarchar, lvarchar)aggrxml(ROW, lvarchar)genxml(lvarchar, ROW)
genxml(ROW)genxml(lvarchar, lvarchar)genxmlhdr(lvarchar, lvarchar)

Обратите внимание на то, что функции addxmlhdr(lvarchar, lvarchar), genxml(lvarchar, lvarchar) и genxmlhdr(lvarchar, lvarchar) могут быть выполнены только в команде EXECUTE FUNCTION.

Исходный код для этих функций занимает около 300 строк текста на C. Код был протестирован с IDS 9.30.TC2 в Microsoft® Windows® 2000 и IDS 9.30.Uc2 в Linux®.

Реализация также включает функцию, полезную при желании изменить код: set_tracing. Эта функция позволяет вам включить трассировку выполнения функции. Необходимо удалить строку "-DMITRACE_OFF=1" из файлов make и добавить код трассировки в исходный код. Более подробную информацию по трассировке можно найти в книге "Серверное программирование на языке C", ссылка на которую приведена в разделе Ресурсы.


Установка

Установка кода примера состоит из трех этапов:

  • Загрузка кода: Все файлы примера должны быть загружены в подкаталог genxml каталога $INFORMIXDIR/extend.
  • Компилирование кода: Вы должны скомпилировать исходный код для вашей платформы. Код примера содержит два файла make: winnt.mak и makefile. Winnt.mak используется для компиляции в Microsoft Windows 2000. Предполагается использование Microsoft Visual C++. Файл makefile используется для компиляции кода на платформах UNIX#x422. Вы должны изменить операторы include в makefile (строка 2) для соответствия платформе.
  • Регистрация функций: Перед использованием рассмотренных выше функций они должны быть зарегистрированы в базах данных, в которых эти функции нужны. Сценарий genxml.sql регистрирует все необходимые функции и создает таблицу genxmlinfo, использующуюся для отслеживания информации о типах документов.

Для удаления функций вы можете выполнить сценарий genxml_d.sql в соответствующей базе данных. Он удалит все функции и таблицу genxmlinfo. Если вы хотите продолжать использовать таблицу, измените сценарии установки и удаления и закомментируйте строки, содержащие таблицу.

Простейшим способом зарегистрировать и удалить регистрацию функций является выполнение сценариев из командной строки:

dbaccess -e jroy genxml <errlog 2<&1

Этот пример использует имя базы данных jroy и перенаправляет выводимую программой dbaccess информацию в файл errlog. При возникновении ошибки сценарий продолжает выполнение следующей команды. Параметр -e указывает программе dbaccess выводить команды на стандартное устройство вывода, для того чтобы увидеть результат каждой команды.


Ограничения

Предоставляемый с данной статьей код содержит два главных ограничения:

  • Строка XML-файла не может превышать 2048 символов.
  • Размер создаваемого XML-документа ограничен 32KB.

Эти ограничения могут быть сняты путем добавления кода, управляющего этими ограничениями. Пример с типом idn_mrlvarchar можно найти на Web-сайте IBM, ссылка на который приведена в разделе Ресурсы. Код, описание типа и способы его использования вы можете также найти в книге "Компоненты с открытым исходным кодом", ссылка на которую тоже приведена в разделе Ресурсы. При использовании реализации, аналогичной idn_mrlvarchar, размер вашего XML-документа может достигать 4TB.

Данная реализация поддерживает большинство типов данных IDS, за исключением типов коллекций (LIST, MULTISET, SET) и типов больших объектов (BLOB, BYTE, CLOB и TEXT).


Заключение

Способность генерировать XML-документы прямо из сервера базы данных может значительно упростить реализацию решения. Упрощается взаимодействие между приложением и базой данных. Это приложение может выполняться на сервере приложений, на web-сервере, быть CGI-программой или автономным приложением. Поскольку код genxml выполняется на сервере базы данных, он легко доступен для любого приложения. Эта возможность способствует повторному использованию кода.

Код genxml демонстрирует мощь объектно-реляционой технологии. Также он демонстрирует по крайней мере еще две вещи:

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


Загрузка

ОписаниеИмяРазмерМетод загрузки
genxml sample codegenxml.zip128 KBFTP|HTTP

Информация о методах загрузки


Ресурсы

Об авторе

Jacques Roy photo

Жак Рой (Jacques Roy) Жак Рой является сотрудником всемирной организации поддержки продаж продуктов фирмы IBM. Он имеет более чем двадцатилетний стаж работы и уже более пяти лет занимается расширяемостью баз данных. Он является автором книги "Informix Dynamic Server 2000: Серверное программирование на языке C" и соавтором книги "Компоненты с открытым исходным кодом для Informix Dynamic Server 9.x".

Помощь по сообщениям о нарушениях

Сообщение о нарушениях

Спасибо. Эта запись была помечена для модератора.


Помощь по сообщениям о нарушениях

Сообщение о нарушениях

Сообщение о нарушении не было отправлено. Попробуйте, пожалуйста, позже.


developerWorks: вход


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


При первом входе в developerWorks для Вас будет создан профиль. Выберите информацию отображаемую в Вашем профиле — скрыть или отобразить поля можно в любой момент.

Выберите ваше отображаемое имя

При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

(Должно содержать от 3 до 31 символа.)


Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Оценить эту статью

Комментарии

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Information Management, XML, WebSphere
ArticleID=108401
ArticleTitle=Генерирование XML из IDS 9.x
publish-date=02252003
author1-email=jacquesr@us.ibm.com
author1-email-cc=

Теги

Help
Используйте форму поиска, чтобы найти любой контент с данным тегом в My developerWorks. Используйте ползунок, чтобы отразить больше или меньше тегов.

КнопкаПопулярные теги отображает самые распространенные теги для данной области контента (например: Java, Linux, WebSphere).

Кнопка Мои теги отображает Ваши теги для данной области контента (например: Java, Linux, WebSphere).

Используйте форму поиска, чтобы найти любой контент с данным тегом в My developerWorks. Кнопка Популярные теги отображает самые распространенные теги для данной области контента (например: Java, Linux, WebSphere). Кнопка Мои теги отображает Ваши теги для данной области контента (например: Java, Linux, WebSphere).