JSon SuperObject 研究2:数据集与JSON对象互转

本文介绍了如何在Delphi中利用JSON与TDataSet之间的互转关系,实现数据集间的通讯与转换。重点在于通过JSON简化数据格式,提高解析效率与资源利用率,特别关注了数据集字段信息的JSON表示与复杂CDS数据结构的转换方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    JSON不能完全替代XML,但绝对是未来的大势所趋,其优点是简单、体积小、解析更快、解析占用资源更少。在delphi中,数据集是最常用数据存取方式。因此,必须建立JSON与TDataSet之间的互转关系,实现数据之间通讯与转换。值得注意的是,这只是普通的TDataset与JSON之间转换,由于CDS包含了Delta数据包,其数据格式远比普通的TDataset更复杂。下面的程序,或许你有不同的想法,如果你的想法更好更快,欢迎一起讨论。今天是2009年最后的几十分钟,重要的并不是写博客,而是想向大家说一声“新年好运,事业有成”!
      数据集字段信息,是一个完整的字典信息。因此,我们在JSON必须也建立字典信息,才能创建数据集的字段信息。我们设置其JSON信息如下:
    COLS:[字段列表信息],如:
"Cols":[{"JsonType":"integer","FieldIndex":0,"FieldType":"Integer","FieldSize":0,"FieldName":"ID","Required":false},{"JsonType":"string","FieldIndex":1,"FieldType":"String","FieldSize":100,"FieldName":"Title","Required":false},{"JsonType":"variant","FieldIndex":2,"FieldType":"Blob","FieldSize":0,"FieldName":"Picture","Required":false}]
数据信息以Data做节点,也是一个数组嵌套记录信息:
"Data":[记录集信息]
废话少说,直接上代码:
unit uDBJson;
interface
uses
  SysUtils,Classes,Variants,DB,DBClient,SuperObject;
type
  TTableJSon = class
  private
     const cstFieldType = 'FieldType';
     const cstFieldName = 'FieldName';
     const cstFieldSize = 'FieldSize';
     const cstJsonType = 'JsonType';
     const cstRequired = 'Required';
     const cstFieldIndex = 'FieldIndex';
     const cstCols= 'Cols';
     const cstData= 'Data';
  public
     class function JSonFromDataSet(DataSet:TDataSet):string;
     class function CreateFieldByJson(Fields:TFieldDefs;ColsJson:ISuperObject):Boolean;
     class function ImportDataFromJSon(DataSet:TDataSet;DataJson:ISuperObject):Integer;
     class function CDSFromJSon(CDS:TClientDataSet;Json:ISuperObject):Boolean;
     class function GetValue(Json:ISuperObject;const Name:string):Variant;
     class function CreateJsonValue(Json:ISuperObject;const Name:string;const Value:Variant):Boolean;
     class function CreateJsonValueByField(Json:ISuperObject;Field:TField):Boolean;
     class function GetValue2Field(Field:TField;JsonValue:ISuperObject):Variant;
  end;
implementation
uses TypInfo,encddecd;
{ TTableJSon }
class function TTableJSon.CDSFromJSon(CDS: TClientDataSet;
  Json: ISuperObject): Boolean;
var
  ColsJson:ISuperObject;  
begin
  Result := False;
  if Json = nil then
     Exit;
  CDS.Close;
  CDS.Data := Null;
  //创建字段
  ColsJson := Json.O[cstCols];
  CreateFieldByJson(CDS.FieldDefs,ColsJson);
  if CDS.FieldDefs.Count >0 then
     CDS.CreateDataSet;
  ImportDataFromJSon(CDS,Json.O[cstData]);
  Result := True;
end;
class function TTableJSon.CreateFieldByJson(Fields: TFieldDefs;
  ColsJson: ISuperObject): Boolean;
var
  SubJson:ISuperObject;
  ft:TFieldType;
begin
  Result := False;
  Fields.DataSet.Close;
  Fields.Clear;
  for SubJson in ColsJson do
  begin
     ft := TFieldType(GetEnumValue(TypeInfo(TFieldType),'ft'+SubJson.S[cstFieldType]));
     if ft= ftAutoInc then  //自增字段不能录入,必须更改
       ft := ftInteger;
     Fields.Add(SubJson.S[cstFieldName],ft,SubJson.I[cstFieldSize],SubJson.B[cstRequired]);
  end;
  Result := True;
end;
class function TTableJSon.CreateJsonValue(Json: ISuperObject;
  const Name: string; const Value: Variant): Boolean;
begin
  Result := False;
  Json.O[Name] := SO(Value);
  Result := True;
end;
class function TTableJSon.CreateJsonValueByField(Json: ISuperObject;
  Field: TField): Boolean;
begin
  Result := False;
  if Field Is TDateTimeField then
     Json.O[Field.FieldName] := SO(Field.AsDateTime)
  else if Field is TBlobField then
     Json.S[Field.FieldName] := EncodeString(Field.AsString)
  else
     Json.O[Field.FieldName] := SO(Field.Value);
  Result := True;
end;
class function TTableJSon.GetValue(
  Json: ISuperObject;const Name: string): Variant;
begin
  case Json.DataType of
     stNull: Result := Null;
     stBoolean: Result := Json.B[Name];
     stDouble: Result := Json.D[Name];
     stCurrency: Result := Json.C[Name];
     stInt: Result := Json.I[Name];
     stString: Result := Json.S[Name];
  end;
end;
class function TTableJSon.GetValue2Field(Field: TField; JsonValue:ISuperObject): Variant;
begin
  if JsonValue.DataType = stNull then
     Result := Null
  else if Field is TDateTimeField then
     Result := JavaToDelphiDateTime(JsonValue.AsInteger)
  else if (Field is  TIntegerField) or (Field is TLargeintField) then
     Result := JsonValue.AsInteger
  else if Field is TNumericField then
     Result := JsonValue.AsDouble
  else if Field is TBooleanField then
     Result := JsonValue.AsBoolean
  else if Field is TStringField then
     Result := JsonValue.AsString
  else if Field is TBlobField then
     Result := DecodeString(JsonValue.AsString)    
end;
class function TTableJSon.ImportDataFromJSon(DataSet: TDataSet;
  DataJson: ISuperObject): Integer;
var
  SubJson:ISuperObject;
  i:Integer;
  iter: TSuperObjectIter;
begin
  if not DataSet.Active then
     DataSet.Open;
  DataSet.DisableControls;
  try
     for SubJson in DataJson do
     begin
       DataSet.Append;
       if ObjectFindFirst(SubJson,iter) then
       begin
          repeat
            if DataSet.FindField(iter.Ite.Current.Name)<>nil then
              DataSet.FindField(iter.Ite.Current.Name).Value :=
                 GetValue2Field(
                 DataSet.FindField(iter.Ite.Current.Name),
                 iter.Ite.Current.Value);
          until not ObjectFindNext(iter) ;
       end;
       DataSet.Post;
     end;
  finally
     DataSet.EnableControls;
  end;
end;
class function TTableJSon.JSonFromDataSet(DataSet:TDataSet):string;
  procedure GetFieldTypeInfo(Field:TField;var Fieldtyp,JsonTyp:string);
  begin
     Fieldtyp := GetEnumName(TypeInfo(tfieldtype),ord(Field.DataType));
     Delete(Fieldtyp,1,2);
     if Field is TStringField then
       JsonTyp := 'string'
     else if Field is TDateTimeField then
       JsonTyp := 'integer'
     else if (Field is TIntegerField) or (Field is TLargeintField) then
       JsonTyp := 'integer'
     else if Field is TCurrencyField then
       JsonTyp := 'currency'
     else if Field is TNumericField then
       JsonTyp := 'double'
     else if Field is TBooleanField then
       JsonTyp := 'boolean'
     else
       JsonTyp := 'variant';
  end;
var
  sj,aj,sj2:ISuperObject;
  i:Integer;
  Fieldtyp,JsonTyp:string;
  List:TStringList;
begin
  sj := SO();
  //创建列
  aj := SA([]);
  List := TStringList.Create;
  try
     List.Sorted := True;
    
     for i := 0 to DataSet.FieldCount - 1 do
     begin
       sj2 := SO();
       GetFieldTypeInfo(DataSet.Fields ,Fieldtyp,JsonTyp);
      
       sj2.S[cstFieldName] := DataSet.Fields.FieldName;
       sj2.S[cstFieldType] := Fieldtyp;
       sj2.S[cstJsonType] := JsonTyp;
       sj2.I[cstFieldSize] := DataSet.Fields.Size;
       sj2.B[cstRequired] := DataSet.Fields.Required;
       sj2.I[cstFieldIndex] := DataSet.Fields.Index;
       aj.AsArray.Add(sj2);
       List.Add(DataSet.Fields.FieldName+'='+JsonTyp);
     end;
     sj.O['Cols'] := aj;
     //创建数据集的数据
     DataSet.DisableControls;
     DataSet.First;
     aj := SA([]);
     while not DataSet.Eof  do
     begin
       sj2 := SO();
       for i := 0 to DataSet.FieldCount - 1 do
       begin
         //sj2.S[IntToStr(DataSet.Fields.Index)] := VarToStrDef(DataSet.Fields.Value,'');
         if VarIsNull(DataSet.Fields.Value) then
           sj2.O[DataSet.Fields.FieldName] := SO(Null)
         else
         begin
           CreateJsonValueByField(sj2,DataSet.Fields);
         end;
       end;
       aj.AsArray.Add(sj2);
       DataSet.Next;
     end;
     sj.O['Data'] := aj;
     Result := sj.AsString;
  finally
     List.Free;
     DataSet.EnableControls;
  end;

end;
end.

调用示例:
//数据集转JSON对象或JSON文本
var
  json:TTableJSon;
  s:string;
begin
  S := json.JSonFromDataSet(ADODataSet1);
  //在用TStringStream读入字符串S,存成文本,看看其格式.
end;
//JSON对象或文本,装载到数据集
var
  json:ISuperObject;
begin
  json := TSuperObject.ParseFile('json.txt',False);
  TTableJSon.CDSFromJSon(cdsJSON,json);
end;

        
        



        







        
          
            
            评论这张
          
        


          
            
              JSon SuperObject 研究2:数据集与JSON对象互转 - yyimen - yyimen的博客
            
            转发至微博
          
        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值