Delphi 6 XML數據綁定

Delphi 6 含有許多更新更強的XML支持功能,增加了XML文件編程,XML數據綁定向導,XML映象和BizSnap(SOAP/XML Web服務)。我在上一篇文章論述了Delphi 6中的XML文件編程(XML Document Programming)。本文是三篇論述Delphi 6中XML功能系列文章的第二篇,論述Delphi 6中的XML數據綁定(XML Data Binding)。

XML文件編程
XMLDocument組件讓我們能夠遍歷和編輯XML文件。但是在上一篇文章中我提到了,我們只能與無類型節點打交道,必須記住節點元素的名字。這意味着無法進行實時編譯調試!幸虧的是,如果Delphi只能處理這樣簡單的問題就不成其爲Delphi了。運用XML的內容相關結構可以做更高級的應用,這就是Delphi 6的XML數據綁定向導(XML Data Binding Wizard)。

XML數據綁定
在Delphi 6的模塊倉庫(Object Repository)中可以找到XML數據綁定向導(XML Data Binding Wizard)。程序員能夠用它生成相應的接口和類來訪問與修改XML文件數據,諸如ClientDataSetXML數據,ADO XML數據,其它XML文件數據(如我們在前文用到的Clinic.xml,本文繼續使用這個簡單的XML文件作示例)。

現在開始吧,啓動Delphi 6,在主菜單上選擇File | New - Other,然後在倉庫中選擇XML Data Binding,如圖1所示。

嚮導有三個頁面。第一頁定義XML綱(Schema)或XML文件(本例用Clinic.xml),如圖2所示。
在資源輸入框內輸入XML綱(Schema)或XML文件。“選項”(Options)對話框定義編碼選項和數據類型映射關係(Data Type map)。以後我們還會談到這些選項。

嚮導的第二頁顯示了樹結構和節點數據類型(亦即嚮導生成了些什麼樣的代碼)。圖3可以看到我的XML文件結構。
可以看到XML文件裏描述的嵌套節點(ClinicsType與ClinicType)和單節點(String)。這時可以打開選項(Options)對話框(圖4),修改編碼(比如修改前綴)和數據類型映射。

嚮導的第三頁顯示生成的相應接口和類。可以把這些結果保存到文件(例如生成Clinic.xdb)。
結果(存儲爲Clinic.xdb文件)顯示如下。我們得到一個ClinicsType類型的Clinics元素,其中包括ClinicType類型的Clinic系列元素。

  <?xml version="1.0"?>
  <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:xdb="http://www.borland.com/schemas/delphi/6.0/XMLDataBinding">
    <xs:element name="Clinics" type="ClinicsType"/>
    <xs:complexType name="ClinicsType">
      <xs:annotation>
        <xs:appinfo xdb:docElement="Clinics"/>
      </xs:annotation>
      <xs:sequence>
        <xs:element name="Clinic" type="ClinicType" maxOccurs="unbounded"/>
      </xs:sequence>
    </xs:complexType>
    <xs:complexType name="ClinicType">
      <xs:sequence>
        <xs:element name="Title" type="xs:string"/>
        <xs:element name="Date" type="xs:string"/>
        <xs:element name="Topics" type="xs:string"/>
      </xs:sequence>
      <xs:attribute name="No" type="xs:string"/>
    </xs:complexType>
  </xs:schema>

文件同時定義ClinicType類型的Clinic元素包含一系列字符串元素(Title, Date和Topics)。

生成代碼
嚮導生成的代碼可以直接在應用中使用。不幸的是,Delphi 6有時會產生“非法操作”的出錯信息。重新執行一遍,它又能工作了。
以下是生成的代碼(Clinic.pas):

  {****************************************************}
  {                                                    }
  {              Delphi XML Data Binding               }
  {                                                    }
  {         Generated on: 2001/11/07 00:37:00          }
  {       Generated from: D:/D6Clinic/src/Clinic.xml   }
  {   Settings stored in: D:/D6Clinic/src/Clinic.xdb   }
  {                                                    }
  {****************************************************}
  unit Clinic;
  interface
  uses xmldom, XMLDoc, XMLIntf;

  type

  { Forward Decls }

    IXMLClinicsType = interface;
    IXMLClinicType = interface;

  { IXMLClinicsType }

  IXMLClinicsType = interface(IXMLNodeCollection)
    ['{06723E03-662D-11D5-81CE-00104BF89DAD}']
    { Property Accessors }
    function Get_Clinic(Index: Integer): IXMLClinicType;
    { Methods & Properties }
    function Add: IXMLClinicType;
    function Insert(const Index: Integer): IXMLClinicType;
    property Clinic[Index: Integer]: IXMLClinicType
      read Get_Clinic; default;
  end;

  { IXMLClinicType }

  IXMLClinicType = interface(IXMLNode)
    ['{06723E04-662D-11D5-81CE-00104BF89DAD}']
    { Property Accessors }
    function Get_No: WideString;
    function Get_Title: WideString;
    function Get_Date: WideString;
    function Get_Topics: WideString;
    procedure Set_No(Value: WideString);
    procedure Set_Title(Value: WideString);
    procedure Set_Date(Value: WideString);
    procedure Set_Topics(Value: WideString);
    { Methods & Properties }
    property No: WideString read Get_No write Set_No;
    property Title: WideString read Get_Title write Set_Title;
    property Date: WideString read Get_Date write Set_Date;
    property Topics: WideString read Get_Topics write Set_Topics;
  end;

  { Forward Decls }

    TXMLClinicsType = class;
    TXMLClinicType = class;

  { TXMLClinicsType }

  TXMLClinicsType = class(TXMLNodeCollection, IXMLClinicsType)
  protected
    { IXMLClinicsType }
    function Get_Clinic(Index: Integer): IXMLClinicType;
    function Add: IXMLClinicType;
    function Insert(const Index: Integer): IXMLClinicType;
  public
    procedure AfterConstruction; override;
  end;

  { TXMLClinicType }

  TXMLClinicType = class(TXMLNode, IXMLClinicType)
  protected
    { IXMLClinicType }
    function Get_No: WideString;
    function Get_Title: WideString;
    function Get_Date: WideString;
    function Get_Topics: WideString;
    procedure Set_No(Value: WideString);
    procedure Set_Title(Value: WideString);
    procedure Set_Date(Value: WideString);
    procedure Set_Topics(Value: WideString);
  end;

  { Global Functions }

  function GetClinics(Doc: IXMLDocument): IXMLClinicsType;
  function LoadClinics(const FileName: WideString): IXMLClinicsType;
  function NewClinics: IXMLClinicsType;

這裏有二個接口類型:IXMLClinicsType和IXMLClinicType;用二個類(TXMLClinicsType和TXMLClinicType)來執行這二個接口。另外還有三個全局函數:GetClinics (獲得根元素),LoadClinics (從外部XML文件加載)和NewClinics (在內存生成新文件)。

用法
使用生成的Clinic.pas單元是很容易的。跟前一篇文章的做法一樣,使用XMLDocument組件(在Inernet標籤內)。不過我們不再使用無類型節點了,我們可以調用GetClinics函數獲得IXMLClinicsType類型。以下是具體操作過程:

在Delphi 6建立一個新的應用(project)
在XML數據綁定向導指引下建立Clinic.pas文件(經過命名存盤 - 譯者)
在主窗體上加入一個XMLDocument組件,其FileName屬性爲Clinic.xml
在主窗體的OnCreate事件中加入以下代碼:
  procedure TForm1.FormCreate(Sender: TObject);
  var
    Clinics: IXMLClinicsType;
  begin
    Clinics := GetClinics(XMLDocument1);
  end;

把Clinics變量放到主窗體中是很有用的,這樣就可以在主窗體運行期間使用Clinics接口。使用IXMLClinicsType變量類型要比以前使用普通XMLDocument組件方便多了。現在可以通過Get_Clinic方法來獲得各個Clinic元素,還可以在特定位置插入新的Clinic元素。用Clinics.Clinic可以獲得節點元素,用Getter和Setter方法可以得到或設置元素值。現在可以直接訪問No, Title, Date, Topics等屬性了:
  procedure TForm1.ButtonGetClick(Sender: TObject);
  var
    Clinic: IXMLClinicType;
  begin
    Clinic := Clinics.Clinic[0];
    EditNo.Text := Clinic.No;
    EditTitle.Text := Clinic.Title;
    EditDate.Text := Clinic.Date;
    EditTopics.Text := Clinic.Topics
  end;

可以在Clinic.pas中看到,Getter和Setter是方法而不是屬性(實際上,我始終認爲使用屬性更清楚些)。但是Delphi 6讓你看到的卻是屬性描述而不是方法本身(Delphi 6的另一個受歡迎的優點)。將上面這段代碼與前一篇文章使用的方法相比較,就能感到操作方便多了。

下面的例子在XML樹的末尾加入一個節點:
  procedure TForm1.ButtonAddClick(Sender: TObject);
  begin
    with Clinics.Add do
    begin
      No := '2001-2-8;  // 8th Clinic of the 2nd series of 2001
      Title := 'Special Kylix 2 Clinic';
      Date := '2001/12/21';
      Topics := 'Kylix 2 New Features'
    end
  end;

如果沒有把XMLDocument組件的AutoSave設置爲真,可以用以下方法保存更動結果:
  procedure TForm1.FormDestroy(Sender: TObject);
  begin
    XMLDocument1.SaveToFile;
  end;

這就是XML數據綁定向導,一個非常方便的方法。它能做得越來越好。

下一篇文章:
我們已經看到了XML數據綁定的優點。不過好象還有點不“滿足”,比方要遍歷各個節點,存取節點值(不單單是字符串類型),雖然可用選項決定,但還是用Delphi 6的XML映象更好,它的功能更強。我們將在下一篇文章論述。

發佈了29 篇原創文章 · 獲贊 3 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章