国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Delphi > 正文

用DELPHI的RTTI實(shí)現(xiàn)對(duì)象的XML持久化

2019-11-18 18:04:02
字體:
供稿:網(wǎng)友
去年我花了很多時(shí)間嘗試用DELPHI進(jìn)行基于xml的WEB應(yīng)用開發(fā)。起初的設(shè)想是很美好的,但結(jié)果做出來的東西很簡(jiǎn)陋。一部分原因就在于XML到Object之間的數(shù)據(jù)綁定實(shí)現(xiàn)太麻煩(另一部分是因?yàn)閷?duì)XSLT不熟,學(xué)習(xí)它花了很多時(shí)間)。

    之前我一直是用DELPHI提供的XML Data binding來做的,基本做法是:先用工具(如XMLSPY)做好一個(gè)XML Schema(XSD),然后用XML Data binding生成DELPHI的接口和類。當(dāng)然,一旦生成好就很方便了,在程序里我只要操作這個(gè)接口就好了,其中各個(gè)Field都會(huì)被變成屬性,并且類型也都如我在XSD中的定義。但問題在于程序在開發(fā)過程中,總是會(huì)有一些變化的,在這種情況下,我就不得不同時(shí)開著XMLSPY修改XSD,然后重新用 XML Data binding的Wizard跑一遍,非常的麻煩。

    所以當(dāng)我想到數(shù)據(jù)集的對(duì)象化后,立即想到也可以用RTTI來實(shí)現(xiàn)Object的XML持久化--其實(shí)DELPHI6開始的SOAP實(shí)現(xiàn)就是用RTTI來實(shí)現(xiàn)Object到SOAP數(shù)據(jù)(就是XML)的轉(zhuǎn)換的。顯然我已經(jīng)是非常的后知后覺了,當(dāng)我在《強(qiáng)大的DELPHI RTTI--兼談需要了解多種開發(fā)語言》一文中說到我的打算時(shí),朋友Lex CHow回復(fù)我說他在大約一年前就做過了這方面的工作,我當(dāng)即跟他要來了他的源碼。lexlib是他寫的是一個(gè)有很多功能的庫,看上去結(jié)構(gòu)有點(diǎn)像.net 的基本類庫(當(dāng)然沒那么大^O^),Object的XML持久化只是其中的很小的一部分。因?yàn)槲抑恍枰@一部分,就沒必要用這整個(gè)一個(gè)庫這么麻煩,于是參考了lexlib并結(jié)合我在《用DELPHI的RTTI實(shí)現(xiàn)數(shù)據(jù)集的簡(jiǎn)單對(duì)象化》中已經(jīng)實(shí)現(xiàn)的部分,做了一個(gè)簡(jiǎn)單的實(shí)現(xiàn):

    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 ) Then        ( 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 ) ) Then                        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.SaveObjToXML(aNode: IXMLNode;  aObj: TPersistent);Var    i : Integer;    pList : TMPropList;    pInfo : PPropInfo;    tmpObj: TObject;begin    If ( aObj Is TMDataSetProxy ) Then        ( 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 ) ) Then                        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;

    這個(gè)實(shí)現(xiàn)應(yīng)該說是很簡(jiǎn)單的。主要是三個(gè)部分(Load和Save的結(jié)構(gòu)是相似的):

    一是對(duì)TMDataSetProxy作特別處理,委托給這個(gè)類自己去處理它的實(shí)現(xiàn),因?yàn)樗c一般的類不同,需要通過ForEach遍歷全部記錄,這其實(shí)就是同時(shí)實(shí)現(xiàn)數(shù)據(jù)集的XML持久化。

    二是對(duì)Class作遞歸處理,當(dāng)然只支持從TPersistent派生的class。

    三是一般的Field簡(jiǎn)單地轉(zhuǎn)成String保存,其中借鑒了lexlib的Filter,只處理那些能簡(jiǎn)單地轉(zhuǎn)成String的數(shù)據(jù)類型,過濾掉那些可能造成轉(zhuǎn)換出錯(cuò)的類型。

    上面的代碼中用到的TMPropList見《用DELPHI的RTTI實(shí)現(xiàn)數(shù)據(jù)集的簡(jiǎn)單對(duì)象化》中的實(shí)現(xiàn)。

    下面是用TMDataSetProxy實(shí)現(xiàn)的數(shù)據(jù)集的XML持久化。免去了需要通過TClientDataSet進(jìn)行的麻煩,并且采用的是用Node記錄字段的方式,.net也是采用這樣的方式,與TClientDataSet所用的用Attribute記錄字段的方式不同。雖然這樣生成的 XML文件將會(huì)略大一些,但是好處也是顯而易見的,特別是我是準(zhǔn)備用在Web應(yīng)用中的,用Node方式記錄的XML,在用XSLT時(shí)會(huì)方便很多。

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;

    下面是一個(gè)簡(jiǎn)單的DEMO,其中包括了對(duì)數(shù)據(jù)集的XML持久化。注意Load的時(shí)候Employee成員連接的是ADODataSet2,它連接到一個(gè)包含了這幾個(gè)字段的表,各字段類型與Employee表相同,但內(nèi)容為空,并且去掉了EmployeeID的Identity。Load完成后,Employee表中這幾個(gè)字段的內(nèi)容將被復(fù)制到此表中。

    TDemoCompany = class( TPersistent )    private        FEmployee : TDSPEmployee;        FCompany  : String;        FCode     : Integer;    published        property Employee : TDSPEmployee Read FEmployee Write FEmployee;        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.SaveObjToXML( XMLDocument1.AddChild( 'Demo' ), demo );        XMLDocument1.SaveToFile( 'temp.xml' );        XMLDocument1.Active := 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.Active := false;        Edit1.Text := demo.Company;        Edit2.Text := IntToStr( demo.Code );        While ( demo.Employee.ForEach ) Do        With ListView1.Items.Add Do        Begin            Caption := IntToStr( demo.Employee.EmployeeID );            SubItems.Add( demo.Employee.FirstName );            SubItems.Add( demo.Employee.LastName );            SubItems.Add( FormatDateTime( 'yyyy-mm-dd', demo.Employee.BirthDate ) );        End;    Finally        demo.Employee.Free;        demo.Employee := Nil;        demo.Free;    End;end;

    終于可以告別那個(gè)麻煩的XML Data binding了,并且以后也不用寫XSD了--雖然有好用的工具,但能省點(diǎn)事終歸是好的。


上一篇:Delphi中實(shí)現(xiàn)漢字拼音聲母查詢

下一篇:用DELPHI的RTTI實(shí)現(xiàn)數(shù)據(jù)集的簡(jiǎn)單對(duì)象化

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
學(xué)習(xí)交流
熱門圖片

新聞熱點(diǎn)

疑難解答

圖片精選

網(wǎng)友關(guān)注

主站蜘蛛池模板: 桐庐县| 册亨县| 教育| 泰来县| 增城市| 栾城县| 南木林县| 特克斯县| 保德县| 黔西县| 安多县| 文成县| 墨竹工卡县| 绵阳市| 闸北区| 隆昌县| 灵台县| 巴彦淖尔市| 赤城县| 东山县| 广昌县| 蓬莱市| 永兴县| 宜都市| 横峰县| 诸暨市| 曲靖市| 江山市| 新蔡县| 翼城县| 北碚区| 洛宁县| 石嘴山市| 麻栗坡县| 肥西县| 五寨县| 神农架林区| 梁山县| 玛多县| 荔波县| 长宁区|