Статьи по программированию
примеры программного кода
Delphi, Kylix, C, C++, SQL, Visual Basic, Bash, Assembler, 1С
Qt, KOL, MFC, Rx Library, Windows, Linux, Mac OS
Работа с XML в Delphi
Опубликовано codeLocker в 08.08.2008 в 10:29.
Формат хранения данных XML уже занял отведенную ему нишу в мировом обществе программистов. А значит людям пишущим на Delphi тоже пора посмотреть на этот формат повнимательней.
История
eXtensible Markup Language (расширяемый язык разметки), или XML как его принято называть, является одним из языков разметки документов, созданным для того, чтобы можно было воспользоваться языком SGML (Standard Generalized Markup Language – стандартный язык общей разметки) в среде World Wide Web. В отличие от HTML, который определяет фиксированный или статистический класс документов, XML позволяет определять собственные пользовательские классы документов.
Язык XML представляет собой упрощенный вариант языка SGML, который облегчает определение новых типов документов и поддержку документов, уже определенных в SGML, а также передачу и совместное использование документов в WEB.
С чего начать
Итак, у нас есть среда разработки – Borland Delphi. Но писать самому всю процедуру обработки строк с их последующим анализом – очень неблагодарное занятие. Тем более если это за нас уже сделали другие. И нам теперь остается только правильно использовать то, что уже имеется. А имеется у нас ActiveX библиотека msxml.dll разработанная «многоуважаемой» Microsoft. А также ее порт на Delphi (msxml.pas) расположенный в директории \Source\Rtl\Win. (Где DelphiPath – путь указанный при установке Delphi).
Пример 1
Как всегда начнем с условия задачи. У нас есть xml-документ (листинг.1). И мы хотим просмотреть его структуру. Для этого нам необходимо сперва создать свежее приложение и перекинуть на него компоненты: TButton и TTreeView (как мы помним XML – структурировано хранилище данных, а для отображения структуры наилучшим компонентов будет TTreeView)
После этого, предварительно не забыв указать в секции uses название модуля "msxml.pas", мы приступаем к работе. Для начала при создании формы мы создадим и экземпляр объекта IXMLDocment2, а при ее уничтожении – высвободим занятую им память:
begin
XML:=CoXMLDocument.Create;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
XML:=nil;
end;
Теперь в реакции кнопки на нажатие напишем следующий код:
procedure TForm1.Button1Click(Sender: TObject);
var I:IXMLElement2;
j:integer;
Root:TTreeNode;
begin
OleCheck(XML.Set_url('D:\test.xml'));
OleCheck(XML.Get_root(I));
Root:=TreeView1.Items.Add(nil,'Root');
ParseXML(Root, I);
end;
Этим кодом мы во первых открываем необходимый для анализа файл ("D:\test.xml"); далее берем указатель на корневой элемент файла и передаем его в процедуру, которая рекурсивно проходит по всем полям документа и соответствующим образом заполняет TreeView элементами XML- структуры и их атрибутами . Код этой процедуры приведен ниже:
if Element.attributes<>nil then
For i:=0 to Element.attributes.length-1 do
begin
prop:=Element.attributes.item(i,NULL);
TreeView1.Items.AddChild(Node,prop.Name+':'+Element.getAttribute(prop.Name));
prop:=NULL;
end;
tmp:=nil;
if Element.children=nil then Exit;
For i:=0 to Element.children.length-1 do
begin
Tmp:=Element.children.item(i,Null) as IXMLElement2;
ParseXML(Node,Tmp);
tmp:=nil;
end;
Для более удобной работы с XML-документами можно предложить использование еще одного интерфейса объявленного все в том же msxml.pas. Этот интерфейс – IXMLDOMDocument; Рассмотрим методику его использования на примере добавления новой записи (Record) в XML документ.
Для начала нам необходимо как и в предыдущем примере создать экземпляр объекта XMLDOMDocument, а для этого над необходимо написать такой код:
DOM:=CoDOMDocument.Create;
После чего мы загружаем необходимый документ и проверяем, нет ли синтаксических ошибок в нем:
if DOM.parseError.reason<>'' then Label1.Caption:=DOM.parseError.reason;
Далее нам необходимо создать новый элемент документа и задать для него соответствующие атрибуты. Это можно сделать при помощи методов:
function createElement(const tagName: WideString): IXMLDOMElement; safecall;
и function createAttribute(const name: WideString): IXMLDOMAttribute; safecall;
Которые создают соответственно элемент структуры и его атрибут. Далее уже при помощи методов интерфейсов IXMLDOMElement и IXMLDOMAttribute мы привязываем атрибуты к соответствующим элементам, а также задаем их значения.
После того, как проделана вся необходимая работа, мы можем записать наши изменения в файл:
procedure save(desination: OleVariant); safecall;
Исходный код данной процедуры приведен в Листинге 2(см. ниже)
Теперь мы уже с вами знаем, как просматривать и добавлять элементы в XML документ, но это конечно же не все возможности XML по хранению данных. Так для больших объемов данных не подлежащих изменению есть другие методы. Такие данные: Тексты программ, простой текст с сохранением всех символов пробелов и табуляций и т.п. записываются в специальные структуры «CDATA». Из которых их потом можно прочитать без потерь информации. Так же может передаваться и бинарная информация (программы, архивы, рисунки, музыка), соответственно закодированная перед этим (алгоритм base64 например). Запись таких данных в XML документ проводится посредством специального Интерфейса IXMLDOMCDATASection путем записи всей информации в его свойство data.
Пример записи такого рода данных показан в Листинге.3
Выводы
Итак, как можно заключить из выше написанного, у формата XML и его использовании при разработке программных продуктов на Delphi есть будущее. Особенно это касается такого свойства XML как легкая кросплатформенная переносимость и независимость. Которое уже вовсю используется разработчиками ПО, которые поддерживают работу своих программ на разных операционных системах, архитектурах и т.д.
Листинг 1. Cтруктура XML-документа
<DataBase name="Customers">
<Metadata>
<fields>
<field name="id" type="1" />
<field name="name" type="2" length="10" />
<field name="address" type="2" length="25" />
<field name="phone" type="2" length="10" />
</fields>
<statistics>
<statistic name="Records" value="5" />
</statistics>
</metadata>
<data>
<record id="1" name="Testing1" address="Testing1 Address" phone="testing1 phone" />
<record id="2" name="Testing2" address="Testing2 Address" phone="testing2 phone" />
<record id="3" name="Testing3" address="Testing3 Address" phone="testing3 phone" />
<record id="4" name="Testing4" address="Testing4 Address" phone="testing4 phone" />
<record id="5" name="Testing5" address="Testing5 Address" phone="testing5 phone" />
</data>
</DataBase>
Листинг 2. Алгоритм отображения структуры XML документа.
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls,msxml, ComCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
TreeView1: TTreeView;
Button2: TButton;
Label1: TLabel;
Button3: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
XML:IXMLDocument2;
procedure ParseXML(RootNode:TTreeNode;Element:IXMLElement2);
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses ComObj;
{$R *.dfm}
procedure TForm1.ParseXML(RootNode:TTreeNode;Element:IXMLElement2);
var i:integer;
Node:TTreeNode;
Prop:Variant;
Tmp:IXMLElement2;
begin
Node:=TreeView1.Items.AddChild(RootNode,'<'+Element.tagName+'>'+':'+Element.text);
if Element.attributes<>nil then
For i:=0 to Element.attributes.length-1 do
begin
prop:=Element.attributes.item(i,NULL);
TreeView1.Items.AddChild(Node,prop.Name+':'+Element.getAttribute(prop.Name));
prop:=NULL;
end;
tmp:=nil;
if Element.children=nil then Exit;
For i:=0 to Element.children.length-1 do
begin
Tmp:=Element.children.item(i,Null) as IXMLElement2;
ParseXML(Node,Tmp);
tmp:=nil;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var I:IXMLElement2;
j:integer;
Root:TTreeNode;
begin
OleCheck(XML.Get_root(I));
Root:=TreeView1.Items.Add(nil,'Root');
ParseXML(Root, I);
end;
procedure TForm1.Button2Click(Sender: TObject);
var DOM:IXMLDOMDocument;
Temp:IXMLDOMNode;
attr:IXMLDOMAttribute;
Records:IXMLDOMNodeList;
i,j:integer;
begin
DOM:=CoDOMDocument.Create;
try
DOM.load('D:\test.xml');
if DOM.parseError.reason<>'' then Label1.Caption:=DOM.parseError.reason;
Temp:=DOM.createElement('record');
attr:=DOM.createAttribute('id');
attr.value:=6;
Temp.attributes.setNamedItem(attr);
attr:=DOM.createAttribute('name');
attr.value:='Testing 6';
Temp.attributes.setNamedItem(attr);
attr:=DOM.createAttribute('address');
attr.value:='Testing 7';
Temp.attributes.setNamedItem(attr);
DOM.getElementsByTagName('data').item[0].appendChild(Temp);
DOM.save('D:\newtest.xml');
finally
DOM:=nil;
end;
end;
Листинг 3. Пример записи неформатированных данных
var DOM:IXMLDOMDOcument;
Node:IXMLDOMCDATASection;
Temp:IXMLDOMNode;
Data:String;
FS:TFileStream;
begin
FS:=TFileStream.Create('D:\rawdata.txt',fmOpenRead or fmShareDenyWrite);
SetLength(Data,FS.Size+1);
FS.ReadBuffer(Pointer(Data)^,FS.Size);
DOM:=CoDOMDocument.Create;
try
Node:=DOM.createCDATASection('cdatasection');
Node.appendData(data);
Temp:=DOM.createElement('BinTest');
DOM.appendChild(Temp);
Temp.appendChild(Node);
DOM.save('D:\rawdata.xml');
finally
DOM:=nil;
FS.Free;
end;
end;
end.
Материал похожий на Работа с XML в Delphi
- Работа с TGA файлами
- Список пользователей 1С
- Работа с Word через OLE
- Работа с автоинкрементальными (AutoInc) полями