Использование XML в среде DelphiDelphi , Интернет и Сети , XMLИспользование XML в среде Delphi
Оформил: DeeCo Автор: А.Календарев Данная статья является переработанным вариантом материалов по XML-технологии опубликованных на сайте автораПоследнее время много внимания уделяется построение систем электронного бизнеса, или как их еще назыают - B2B (business to business). Учитывая рекомендации по построению обменных потоковых систем координирующего интернет-технологий органа - WWW Consortium: акцент сделан в сторону XML-технологий и построение систем обмена XML-документами. Преимущество использования XML в электронном бизнесе - высокая эффективность B2B систем при низких затратах на ее создание за счет четкого и наглядного представления структурированной информации, возможность использования современных сетевых протоколов и создания бизнес-систем реального времени. Независимость представления информации в виде XML документов позволяет разным, участвующим в электронном бизнесе, фирмам производить независимое друг от друга ПО. Во всех системах обмен, как правило, строится по одинаковой схеме, с использованием HTTP запросов. В качестве протокола защиты информации применяется протокол SSL (но это отдельная тема). Один из возможных вариантов обработки XML сообщения является построение BIN/CGI (ISAPI)-приложений или COM (серверных) компонент, формирующих или обрабатывающих XML-документы. С одной стороны, приложение выступает в качестве клиента, которое в режиме POST выдает HTTP запрос, с другой стороны, находится WEB сервер на стороне которого осуществляется обработка запроса и выдача ответа. В информационном обмене используются XML-документы. Один из наиболее эффективных вариантов реализации - использование существующего XML-парсера, поддерживающего DOM модель. Такой парсер является дистрибутивной поставкой Win`98 или составной частью IE 4,7 и выше (для Win`95) и представляет COM сервер, находящийся в библиотеке msxml.dll. Модель компонентных объектов (COM) - представляет инкапсулированные данные и методы в единую сущность и способ доступа к ним через систему интерфейсов. Средствами Delphi достаточно просто осуществить доступ к классам COM-объекта (в одном COM-сервере может быть включено несколько классов). Доступ к объектам осуществляется путем инициализации экземпляра класса через систему интерфейсов. Описание интерфейсов осуществляется языком определения интерфейсов (IDL), которое возможно осуществить средствами среды автоматически. Средствами Delphi осуществляется импорт из COM-сервера msxml.dll, строится файлы описания интерфейса IDL и файл бинарноого описания типов библиотеки - TLB. Данная операция осуществляется через системное меню: Project | Type Library Import… (рис 1). Далее появляется диалоговое окно (рис 2), в котором необходимо выбрать COM-объект (в нашем случае объект зарегистрирован под именем "Microsoft.XMLDom (Version 2.0)" ) и создать TLB-файл (кнопка Create Unit). Используя TLB-файл, среда генерирует "паскалевский" файл описания COM-сервера - MSXML_TLB.pas
В файле MSXML_TLB.pas описаны все интерфейсы, константы и соклассы COM-сервера. Для доступа к объектам COM-элемента, необходимо в директиве USES добавить имя файла описания библиотеки (MSXML_TLB.pas). Ниже представлена простейшая программа, использующая DOM стандартный анализатор msxml.dll, которая загружает XML-документ и отображает его в элементе текстового поля Memo1. uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, OleServer, MSXML_TLB, StdCtrls; type TForm1 = class(TForm) Button1: TButton; Memo1: TMemo; procedure Button1Click(Sender: TObject); end; var Form1: TForm1; implementation {$R *.DFM} procedure TForm1.Button1Click(Sender: Tobject); var coDoc: CoDOMDocument; / * объявление сокласса объекта DOMDocument; * / var Doc: IXMLDOMDocument; / * класс, согласованный с интерфейсом IDOMDocument; * / begin Doc := coDoc.Create; / * создание экземпляра объекта DOMDocument; * / Doc.load('data.xml'); / * вызов метода Load экземпляра объекта DOMDocument; * / Memo1.Text := Doc.xml; / * доступ к свойстве xml экземпляра объекта DOMDocument; * / end; end.Концепция DOM - объектная модель документа Каждый XML документ представляется в виде набора множества объектов (классов), с помощью которых возможен доступ к отдельным элементам (полям объекта). DOM - интерфейс описывает доступ как к простым объектам типа DOMString или CharacterData, так и к частям или отдельным элементам XML документа: DOMFragmentElement, DOMNode, DOMElement. Ниже приведены самые важные свойства и методы объектов XMLDOMDocument, XMLDOMNode, XMLDOMNodeList. Необходимо отметить, что представленные ниже методы и функции объектов DOM модели (Document Object Model) используются Microsoft XML-анализатором msxml.dll и несколько шире, чем утвержденная W3C Консорциумом DOM модель. Более полное описание интерфейса DOM объектов можно найти на www.msdn.microsoft.com/xml
Использование XML в бизнесе. Для более ясной картины необходимо пояснение, а зачем все это нужно с тем, что бы понять, как это работает… При построении B2B или корпоративной ERP системы, при организации информационного обмена XML-документами между предприятиями или филиалами пр-я, используются эффективно себя зарекомендовавшая система передачи информации на основе имеющихся WEB серверов по HTTP протоколам. С одной стороны, приложение выступает в качестве клиента, которое в режиме POST выдает HTTP запрос, с другой стороны, находится WEB сервер, на стороне которого осуществляется обработка запроса и выдача ответа. В качестве обмена используются XML-документы. Например, в простой корпоративной ERP системе бухгалтерской программе (АСУ Бухучет) необходимо сформировать некий запрос на выписку накладной и передать его в филиал, который имеет склад (АСУ Склад). АРМ Аналогичная постановка задачи при создании В2В системы, когда Предприятие А запрашивает наличие продукции (делает заказ на приобретение) у Поставщика В. Предприятие А и его программа выступает в качестве клиента. Склад обслуживает Поставщик В, у которого находится складской комплекс БД на SQL сервере. Обмен осуществляется через корпоративный WEB сервер Поставщика В. Ниже представлен следующий типовой алгоритм обмена: Рис 3.
Несколько слов об организации документооборота. Общим правилом разработки системы обмена XML документами является:
Каждый XML документ, подобно HTML документу, должен состоять из заголовка
сообщения (информация заключенная тагами Заголовок (Рис 4), в отличие HTML документа, должен содержать разного рода
служебную информацию, в том числе информацию о типе передаваемого документа и
процессе его обработки. В информационную обработку поступает тело документа,
т.е. содержательная часть обрамленная тагами Для запущенного сервером Процесса, алгоритм обработки предпочтительно (но не обязательно) строить следующим образом: Рис 6.
Некоторые принципиальные моменты
при создании клиентской части
Как уже пояснялось, при создание XML-документа используется его представление в виде DOM модели. Ниже приведен пример части текста Delphi программы создания заголовка xml сообщения. procedure TThread1.HeaderCreate(Sender: Tobject); var coDoc : CoDomDocument ; // объявление сокласса, необходим для создания Doc : DomDocument ; // объекта XMLDomDocument r : IXMLDOMElement; // объявление объектов DOMElement Node : IXMLDOMElement; // txt : IXMLDOMText; // DOMText attr : IXMLDOMAttribute; // DOMAttribute begin Doc:=coDoc.Create; // создание документа DOM Doc.Set_async(false); // установка синхронного режима обрабработки Doc.LoadXML('<Header/>'); // начальная инициация DOM документа r:=Doc.Get_documentElement; // получение адреса корневого элемента Node := Doc.createElement ( 'Sender'); // создание DOMElement (таг <Sender>) txt := Doc.createTextNode( 'ООО "Тайфун"'); // создание техстового узла 'ООО "Тайфун"' Node.appendChild(txt); // присвоение узлу <Sender> значение // техстового узла 'ООО "Тайфун"' r.appendChild(Node); // добавление элемента <Sender> в корень // документа как дочернего Node := Doc.createElement ( 'From'); // аналогичные операции для тага <From> txt := Doc.createTextNode( 'http://tayfun.ru/xml/default.asp'); Node.appendChild(txt); r.appendChild(Node); Node := Doc.createElement ( 'To'); // аналогичные операции для тага <To> txt := Doc.createTextNode( 'http://irbis.ru'); Node.appendChild(txt); r.appendChild(Node); Node := Doc.createElement ( 'TypeDocument'); // создание DOMElement (<TypeDocument Id>) Att := Doc.createAttribute ( 'Id ', ' Order'); // создание узла XMLDOMAttribute Node.appendChild(Att); // <TypeDocument Id="Order"/> r.appendChild(Node); end; Следует отметить, что объявление переменной coDoc : CoDomDocument и Doc : DomDocument , а также ее создание методом Create ( Doc:=coDoc.Create;) осуществляется один раз. Объявление переменной находится в секции описания глобальных переменных, а не в локальной процедуре, как было продемонстрировано для наглядности в данном примере (т.е. одна глобальная переменная типа DomDocument на один программный модуль). Результатом работы вышеприведенной программы будет созданный заголовок <Header>, приминительно к нашему примеру xml-документа: изображен на рис. 7. Рис 7. Рис 8. Основное приемущество передачи информации в виде XML-документов в том, что существует возможно формировать сообщение, используя независимые структуры таблиц в СУБД как на принимаемой, так и на передаваемой стороне. Используя наш пример, пусть требуется передать информацию об инвойсах Предприятия А, из СУБД имеющий структуру, изображенную на рис. 6 Для формирования xml-документа, содержащего инвойс первоначально строится SQL-запрос (запрос А) с информацией о самом инвойсе: SELECT * FROM Invoice_General WHERE InvoiceNum = :num // :num - параметр, который задает номер инвойса. и далее строится SQL-запрос (запрос В) информация о товарах, описываемых в инвойсе (детальная спецификация): SELECT Goods,Qulity,Price, HZ_cod FROM Goods WHERE InvoiceNum = :num // :num - параметр, который задает номер инвойса. Ниже представлена часть программы, формирующей тело xml-документа: procedure TThread1.DataBodyCreate(Sender: Tobject); var //coDoc : CoDomDocument ; // объявление сокласса и объекта XMLDomDocument //Doc : DomDocument ; // должно быть глобальным, для всего модуля. r : IXMLDOMElement; // объявление объектов DOMElement Node, Node2 : IXMLDOMElement; // DOMElement; Node3, Node4 : IXMLDOMElement; // txt : IXMLDOMText; // DOMText str : String; // InvoiceNumber: integer; - глобальная переменная - имеет значение 987654 // queryA, queryB : String; - глобальная переменная, имеет значение, соответсвующее запросу // queryA - запрос А генеральная информацией об инвойсе // queryB - запрос B информация о товарах, описываемых в инвойсе (см. текст) begin Query.Close; // закрывает запрос для доступа Query.Text := queryA; // см. по тексту "запрос А" Query.Params[0].AsInteger := InvoiceNumber; // присваивание значения параметров Query.ExecSQL; // выполнение запроса Query.Open; // открытие доступа к данным запроса r:=Doc.Get_documentElement; // получение адреса корневого элемента Node2 := Doc.createElement ( ' Request '); // создание DOMElement (таг <Request>) Node := Doc.createElement ( 'Invoice'); // создание DOMElement (таг <Invoice >) r.appendChild(Node2); // добавление элемента <Request> в корень Node2. appendChild(Node); // добавление элемента <Invoice> в <Request> Node3 := Doc.createElement ( 'Depurture') ; // создание DOMElement (таг <Depurture>) Node. appendChild(Node3); // добавление элемента <Depurture> в <Invoice> str:= Query.FieldByName('Depurture').AsString; // обращение к полю 'Depurture' запроса txt := Doc.createTextNode( str); // создание техстового узла = значению поля Node.appendChild(txt); // присвоение узлу <Invoice> значение // техстового узла, переменной str // аналогичные операции для тага <Destination>, <DataSend>, <DataDepurture>, <Currency> // <DestinationCompany> (поле DB "Consignee" ) Node := Doc.createElement ( 'Destination'); str:= Query.FieldByName('Consignee ').AsString; // имя поля БД может и не совпадать с именем txt := Doc.createTextNode( str); // тага, в этом приемущество использования Node.appendChild(txt); // DOM интерфейса перед СУБД, имеющим // поддержку XML-интерфейса, типа ORACLE 8i ... // или Ms SQL 2000 // формирование запроса на спецификацию по товарам Query.Close; // закрывает запрос для доступа Query.Text := queryВ; // см. по тексту "запрос В", информац. О товарах Query.Params[0].AsInteger := InvoiceNumber; // присваивание значения параметров Query2.ExecSQL; // выполнение запроса Query.Open; // открытие доступа к данным запроса Node3 := Doc.createElement ( ' Imems') ; // создание DOMElement (таг <Imems>) Node. appendChild(Node3); // добавление элемента <Imems> в <Invoice> while not Eof.Query do begin // цикл по всем строкам запроса Node4 := Doc.createElement ( 'Imem'); Node3.appendChild(Node4); // добавление элемента <Imem> в <Imems> str:= Query.FieldByName('Price').AsString; // формирование данных для тага <Price> txt := Doc.createTextNode( str); Node.appendChild(txt); ... // аналогичные операции для тагов <HZ_Cod>, <Quality>, <GoodName> end; end; В результате выполнения данной процедуры формируется следующий текст XML-документа: Для формирования запроса используется метод Open объекта IXMLHttpRequest: procedure Open(const bstrMethod, -тип метода = "POST" bstrUrl, -Url адрес сервера varAsync, -режим связи асинхронный / синхронный = true bstrUser, -имя пользователя для аутентификации bstrPassword) - парольСоздании серверной части обработки документа Как было отмечено ранее, обработка HTTP запроса может осуществляться либо CGI-приложениями, либо Java-сервлетами. Возможен и вариант написания ASP-страниц. Но в этом случае передача данных возможна только методом "GET" через строку запроса. Хотя, обработка HTTP запроса ASP-страниц работает более эффективнее, чем CGI-приложением. Однако, на мой взгляд, без разницы, как обрабатывать, а важнее решить вопрос - как построить программму обработки, а не какими средствами. Если из предыдущей главы мы рассмотрели варианты формирования XML-документ, то задача серверного приложения обратная - разбор XML-документов. Ниже представлена часть программы, осуществляющей разбор xml-документа: procedure Tthread1.DataParser(Sender: Tobject); var r,FNode : IXMLDOMElement; // объявление объектов DOMElement Str,Filename : String; parm : String; CoDocXML, CoDocXSL, CoDocResult : CoDomDocument ; // объявление сокласса и XMLDoc, XSLDoc, ResultDoc : DomDocument ; // объекта XMLDomDocument // HttpStr : String; - глобальная переменная, содержащая строку HTTP запроса Begin XMLDoc:=coDocXML.Create; // создание документа XMLDoc XMLDoc.Set_async(false); // установка синхронного режима обрабработки XMLDoc.LoadXML(HttpStr); // загрузка DOM документа из строки HttpStr r:=Doc.Get_documentElement; // получение адреса корневого элемента FNode:= r.SelectSingleNode("//TypeDocument"); // получение значения элемента <TypeDocument> FileName:= FNode.GetAttibute("id"); // получение значения аттрибута id="Order" FileName:= FileName+".xsl"; // и формирование имени файла Order.xsl XSLDoc:=coDocXSL.Create; // создание документа XSLDoc XSLDoc.Set_async(false); // установка синхронного режима обрабработки XSLDoc.LoadXML(FileName); // загрузка DOM документа из файла Order.xsl ResultDoc:=coDocResult.Create; // создание документа XMLDoc ResultDoc.Set_async(false); // установка синхронного режима обрабработки ResultDoc.validateOnParse := true; // установка проверки разбора XMLDoc.transformNodeToObject(XSLDoc, ResultDoc); // разбор XMLDoc по XSL-шаблону Str:= ResultDoc.text; // переменной Str присваивается текстовое значение // результирующего документа. FNode:= r.SelectSingleNode("//InvoiceNumber"); // поиск элемента <InvoiceNumber> parm:= FNode.text; // и получение значения элемента Query.Close; // закрывает запрос для доступа Query.Text := Str; Query.Params[0].AsString := parm; // присваивание значения параметра Query.ExecSQL; // выполнение запроса end; Вся изюминка разбора заключается в применении XSL-шаблона, который сформирован для каждого типа документа индивидуально. Результатом разбора является строка SQL-запроса. Впоследствие выполнение сформированной строки SQL-запроса осуществит необходимые изменения данных в СУБД. Приимущество использования разбора через щаблон еще и в том, что получается некая гибкость данных, и получается полная независимость работы алгоритма от программного кода. Ниже приведен используемый для обработки документа типа ORDER текст XSL-шаблона: <!-- файл Order.xsl --> <xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl"> <xsl:template match="/"> <!-- применяем шаблон ко всему документу, начиная с корневого элемента "/" --> <HTML> <xsl:for-each select="//header"> <!-- формирование запроса для записи данных --> <!-- в таблицу регистрации приходящих сообщений TABREG --> INSERT into TABREG ( FROM, TO, TYPEDOC,body) VALUES( ' <xsl:value-of select="from" />' ,' <xsl:value-of select="to" />','<xsl:value-of select="TypeDocument/@id" />' ) </xsl:for-each> <!-- формирование запроса для записи данных в таблицу GOODS --> <!-- информация о товарах --> <xsl:for-each select="//item"> INSERT into GOODS ( invoiceNumber, name, price, quality) VALUES( ' :num', '<xsl:value-of select="name" />' , '<xsl:value-of select="price" />', '<xsl:value-of select="quality" /> ' ) </xsl:for-each> </HTML> </xsl:template> </xsl:stylesheet> Поясняя вышеприведенный пример, надо отметить, что использование пары тагов <HTML> и </HTML> носит формальный характер, т.к. после разбора в результирующем XML-документе формально должен присутствовать хотябы один узел. Метод ResultDoc.text присваивает текстовае значение полученного в ходе разбора XML-документа ResultDoc. В этом случае значением является все то, что обрамлено пары тегов <HTML> и </HTML>, т.е. сформированный нами SQL-запрос. Другой особенностью написания программы надо отметить возможность использования SQL-параметра :num. Использование параметра позволяет упростить текст xsl-шаблона. Определение значение соответствующих элементов узлов XML-документа определякется первоночально выбора по имени соответствующего узла, например: FNode := r.SelectSingleNode(" //InvoiceNumber"); // поиск элемента >InvoiceNumber> и далее использование свойства text: parm := FNode.text; // и получение значения элемента >InvoiceNumber>Коротко об XSL Абревиатура XSL происходит от eXtensible Stylesheet Language - язык форматирования таблиц стилей (XML данных). Как понятно из заголовка eXtensible Stylesheet Language (XSL) используется для форматирования XML данных. По определению W3C XSL состоит из двух частей:
При помощи XSLT мы можем отобрать нужные нам данные из XML файла, и оформить их в виде для предоставления пользователю. Например, в нашем случае мы преобразовали XML данные в виде SQL запроса. Классическое применение XSL - это, как правило форматирование данных в виде HTML страниц или более редкое представление в виде RTF файлов. XSL файл описывает шаблон (template), согласно которому будет совершаться преобразование XML данных. Возращаясь к xsl-шаблонам, в XSLT можно выделить следующие элементы (директивы):
В заключение, необходимо отметить, что использование стандартного XML-парсера msxml.dll является не единственным средством разбора и создания XML-документов. Например, для создание XML документов эффективно использовать компоненты TPageProduser и TТableProduser. Но, данная статья лишь подчеркивает широту и возможность применения на практике DOM модели . Автор будет очень благодарен за отзывы об актуальности темы, общем содержании, стиле изложения, а также всем остальным комментариям, которые помогут в дальнейшем улучшить качество написания сборника статей и выпуску книги, освещающую тему практической стороны использования XML-документов в электронной коммерции. Более подробную информацию о практической стороне применения электронных документов можно почерпнуть на авторском сайте www.eDocs.al.ru Также на авторском сайте планируется разместить исходные тексты и примеры. Статья Использование XML в среде Delphi раздела Интернет и Сети XML может быть полезна для разработчиков на Delphi и FreePascal. Комментарии и вопросыМатериалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007 |