XML persistence of objects with Delphi RTTI

xiaoxiao2021-03-06  38

XML persistence of objects with Delphi RTTI

[Mental Studio] Raptor [blog]

Last year I spent a lot of time attempting to develop XML-based web application development with Delphi. The initial imagination is very beautiful, but the things that make it are very simple. Part of the reason is that the data binding between XML to Object is too much trouble (the other part is because it is not familiar with XSLT, and learning it has spent a lot of time).

I have always made XML Data Binding provided by Delphi, the basic practice is to do an XML Schema (XSD) with tools (such as XMLSPY) and then generate Delphi interfaces and classes with XML Data Binding. Of course, once it is good, it is very convenient. In the program, I just have to operate this interface, all of which are becomes attribute, and the type is also as defined in XSD. But the problem is that the program will always have some changes during the development process. In this case, I have to modify the XSD in this case, and then reuse the XML Data Binding Wizard once, very trouble.

So after I think the object of the data set, I immediately thought that I can use RTTI to implement Object's XML persistence - in fact, the SOAP implementation started by Delphi6 is to implement Object to SOAP data (already XML). Conversion. Obviously I was already very late, I said that when I said in "Strong Delphi RTTI", I need to understand a variety of development languages. "When I planned me, my friend Lex Chow replied to me said that he was about one I have done this work before the year, I immediately came to him with him. Lexlib is a library that he written is a library having a lot of functions. It looks a bit like .NET's basic class library (of course not so big ^ o ^), Object's XML persistence is just a small part. Because I only need this part, I don't have to use this whole library so trouble, so I have made a simple one in the part of Lexlib and combined with my simple object of Delphi's RTTI to achieve data set. achieve:

TMXMLPERSISTENT = Class (TOBJECT)

public

Class Procedure Loadobjfromxml (anode: IXMLNode; AOBJ: TPERSISTENT);

Class Procedure SaveObjtoxml (anode: IXMLNode; AOBJ: TPERSISTENT);

END;

Const

Defaultfilter: TTYPEKINDS = [Tkinteger, Tkchar, TkenuMeration,

Tkfloat, Tkstring, Tkset, Tkwchar, Tklstring, Tkwstring, Tkint64];

{TMXMLPERSISTENT}

Class Procedure TMXMLPERSISTENT.LOADOBJFROMXML (anode: IXMLNode;

AOBJ: TPERSISTENT);

VAR

i: integer;

PList: tmproplist;

PINFO: PPROPINFO;

Tmpobj: TOBJECT;

Begin

IF (aobj is tmdatasetproxy)

(AOBJ As TmdataSetProxy) .loadFromxml (anode)

Else

Begin

PList: = TMProplist.create (AOBJ);

Try

For i: = 0 to PLIST.PROPCOUNT - 1 DO

Begin

Pinfo: = plist.props [i]; if (pinfo ^ .proptype ^ .kind = tkclass) THEN

Begin

Tmpobj: = TOBJECT (Integer (getPropValue (Aobj, Pinfo ^ .name));

IF (Assigned (Tmpobj) And (Tmpobj IS TPERSIStent).

Loadobjfromxml (Anode.childNodes [WideString (Pinfo ^ .name),

Tmpobj as tpersistent;

End

Else if (pinfo ^ .proptype ^ .kind in defaultfilter) THEN

SetPropValue (aobj, pinfo ^ .name,

String (Anode.childNodes [WideString (Pinfo ^ .Name)]. Text);

END;

Finally

Plist.free;

END;

END;

END;

Class Procedure TMXMLPERSISTENT.SAVEOBJTOML (anode: IXMLNode;

AOBJ: TPERSISTENT);

VAR

i: integer;

PList: tmproplist;

PINFO: PPROPINFO;

Tmpobj: TOBJECT;

Begin

IF (aobj is tmdatasetproxy)

(AOBJ As TmdataSetProxy) .savetoxml (anode)

Else

Begin

PList: = TMProplist.create (AOBJ);

Try

For i: = 0 to PLIST.PROPCOUNT - 1 DO

Begin

Pinfo: = pList.props [i];

IF (Pinfo ^ .propType ^ .kind = tkclass) THEN

Begin

Tmpobj: = TOBJECT (Integer (getPropValue (Aobj, Pinfo ^ .name));

IF (Assigned (Tmpobj) And (Tmpobj IS TPERSIStent).

SaveObjToxml (anode.addchild (WideString (pinfo ^ .name),

Tmpobj as tpersistent;

End

Else if (pinfo ^ .proptype ^ .kind in defaultfilter) THEN

Anode.addchild (WideString (Pinfo ^ .Name) .Text: =

GetPropValue (AOBJ, PINFO ^ .Name);

END;

Finally

Plist.free;

END;

END;

END;

This implementation should be said to be very simple. Mainly three parts (LOAD and SAVE structure are similar):

First, it is specially handled for TMDataSetProxy, entrusting this class to handle its implementation, because it is different from the general class, it is necessary to pass all records through Foreach, which is actually the XML persistence of the data set.

The second is to recursively handle Class, which is only supported from TPERSISTENT.

Third, the general Field is simply converted to String Save, which draws on the Filter of Lexlib, only dealing with those data types that can simply turn into string, filter out the type that may cause conversion error.

The TMProplist used in the above code is shown in the implementation of "Simple Objecttization" with Delphi's RTTI to implement the data set. Below is the XML persistence of the data set implemented with TMDataSetProxy. It is necessary to use the TClientDataSet, and use the Node record field, .NET is also used in such a way that the way TclientDataSet is used in the way. Although this generated XML file will be slightly large, it is also an obvious, especially I am ready to use the XML recorded in the web application, which is more convenient to use XSLT.

Procedure tmdatasetProxy.LoadFromxml (anode: ixmlnode);

VAR

I, J: Integer;

PINFO: PPROPINFO;

Prow: ixmlnode;

Begin

For j: = 0 to anode.childnodes.count - 1 do

Begin

FDataSet.Append;

Prow: = anode.childnodes [j];

For i: = 0 to fproplist.propcount - 1 do

Begin

Pinfo: = fproplist.props [i];

IF (pinfo ^ .proptype ^ .kind in defaultfilter) THEN

Setvariant (i,

String (ProW.childNodes [WideString (Pinfo ^ .Name)]. Text));

END;

Endedit;

END;

FDataSet.first;

END;

Procedure TmdataSetProxy.savetoxml (anode: ixmlnode);

VAR

i: integer;

PINFO: PPROPINFO;

Prow: ixmlnode;

Begin

While foreach do

Begin

Prow: = anode.addchild ('row');

For i: = 0 to fproplist.propcount - 1 do

Begin

Pinfo: = fproplist.props [i];

IF (pinfo ^ .proptype ^ .kind in defaultfilter) THEN

Prow.addchild (WideString (pinfo ^ .name) .Text

: = GetVariant (i);

END;

END;

END;

Below is a simple DEMO, including XML persistence for the data set. Note that the Employee member is adodataset2 when LOAD is connected, which is connected to a table containing these fields, the types of fields are the same as the Employee table, but the content is empty, and remove the Identity of EMPLOYEEID. After the LOAD is complete, the content of these fields in the Employee table will be copied to this table.

TDemoCompany = Class (TPERSIStent)

Private

Femployee: tdspemployee;

Fcompany: string;

Fcode: integer;

Published

Property Employee: TDSPEMPLOYEEEEEEEE: TDSPEMPLOYEEEEEEEEE: TDSPEMPLOYEEEEEEEE: TDSPEMPLOYEEEEEEE:

Property Company: String Read FCompany Write Fcompany;

Property Code: Integer Read Fcode Write Fcode; End;

Procedure TFORM1.SAVECLICK (Sender: TOBJECT);

VAR

Demo: tdemocompany;

Begin

Demo: = tdemocompany.create;

Demo.employee: = tdspemployee.create (adodataset1);

Demo.company: = 'DEMO Company';

DEMO.CODE: = 987654;

Try

XmlDocument1.active: = true;

TMXMLPERSISTENT.SAVEOBJTOML (XmlDocument1.Addchild ('Demo'), Demo;

XmlDocument1.savetofile ('Temp.xml');

XMLDocument1.act: = false;

Finally

Demo.employee.free;

Demo.employee: = NIL;

Demo.Free;

END;

END;

Procedure TFORM1.LOADCLICK (Sender: TOBJECT);

VAR

Demo: tdemocompany;

Begin

Demo: = tdemocompany.create;

Demo.employee: = tdspemployee.create (adodataset2);

Try

XmlDocument1.active: = true;

XmlDocument1.LoadFromfile ('Temp.xml');

TMXMLPERSISTENT.LOADOBJFROMXML (XmlDocument1.childNodes.last, Demo);

XMLDocument1.act: = false;

Edit1.Text: = DEMO.COMPANY;

Edit2.Text: = INTTOSTR (DEMO.CODE);

While (demo.employee.Foreach) DO

With listview1.items.add do

Begin

CAPTION: = INTOSTR (Demo.employee.employeeid);

Subitems.Add (demo.employe.firstname);

Subitems.Add (demo.employee.lastname);

Subitems.Add (Formator-mm-DD ', Demo.employee.birthdate);

END;

Finally

Demo.employee.free;

Demo.employee: = NIL;

Demo.Free;

END;

END;

Finally, I can bid farewell to the trouble XML Data Binding, and I don't have to write XSD in the future - although there is a tools, it is good to save things.

[Mental Studio] Raptor JAN.29-05

转载请注明原文地址:https://www.9cbs.com/read-62350.html

New Post(0)