Delphi Clinic C++Builder Gate Training & Consultancy Delphi Notes Weblog Dr.Bob's Webshop
Dr.Bob's Delphi Notes Dr.Bob's Delphi Clinics Dr.Bob's Delphi Courseware Manuals
 Dr.Bob Examines... #135
See Also: Dr.Bob's Delphi Papers and Columns

Analysing TClientDataSet data files
In this article, I'll demonstrate how to analyse TClientDataSet data files in XML or CDS format and produce a plain text or HTML output with the results.
Based on the original article from 2001, where I describe how to analyse a BDE Alias (and later a dbExpress connection to a database), I recently had the need to analyse a set of XML files that contained the data from a collection of TClientDataSets. This actually makes the analysing process a lot easier, since I only had to assign the filename to the TClientDataSet (it supports both the XML and binary CDS format) and process the FieldDefs and IndexDefs.

Instead of producing HTML output, I needed two possible results: one with tabs (so I could use the resulting output and have MS-Word generate a nice table from it), and a comma separated result, so we could import the definitions themselves in a meta-table database.
The program below contains a Delimit: Char variable that is used to store the tab character (by default) or the second command-line argument (where you can pass a comma or any other character you want to use as delimiter).

  program XMLlias;
  {$APPTYPE CONSOLE}
  uses
    Classes, DB, DBClient;

  const
    TAB = #9;

  var
    i: Integer;
    Delimit: Char;

  begin
    with TClientDataSet.Create(nil) do
    try
      FileName := ParamStr(1);
      if ParamCount > 1 then Delimit := ParamStr(2)[1]
                        else Delimit := TAB;
      Open; // TClientDataSet

      if Delimit = TAB then // write tablename and records
      begin
        writeln(FileName,' ',RecordCount:4);
        for i:=1 to Length(FileName)+5 do write('=');
        writeln;
      end;

      // write field (meta) data definitions
      writeln('Field',Delimit,'Name',Delimit,'Type',Delimit,'Req');
      for i:=0 to Pred(FieldCount) do
      begin
        write(i,Delimit);
        write(Fields[i].DisplayName,Delimit);
        write(FieldDefs[i].FieldClass.ClassName);
        if FieldDefs[i].DataType = ftString then
          write('[',FieldDefs[i].Size,']');
        if FieldDefs[i].Required then write(Delimit,'Yes');
        writeln
      end;

      // write index (meta) definitions
      IndexDefs.Update;
      if IndexDefs.Count > 0 then
      begin
        writeln;
        writeln('Index',Delimit,'Name',Delimit,'Fields');
        for i:=0 to Pred(IndexDefs.Count) do
        begin
          write(i,Delimit);
          write(IndexDefs[i].DisplayName,Delimit);
          write(IndexDefs[i].Fields);
          writeln
        end
      end;
      Close // TClientDataSet
    finally
      Free // TClientDataSet
    end
  end.

I apolgise for using the with statement here, but for small utility like console applications like this, with no ambuguity regarding the scope, I felt it could do little harm...


This webpage © 2011 by Bob Swart (aka Dr.Bob - www.drbob42.com). All Rights Reserved.