把别人发来的 JSON 解析为 Delphi 的对象

需求

这个 JSON 是其它语言生成的,在 Delphi 程序里面,如果能把它变成对象,后继的代码就会更简单。

数据

{"pkt_type":"scan_report","gw_addr":"c7ef72a011b6","time":"2024-07-20 18:49:33","data":{"flags":5,"pkt_sn":2299,"report_type":"le5_raw","pkt_total":1,"pkt_index":0,"dev_total":1,"dev_num":1,"dev_infos":[{"addr":"e91440214207","rssi":-59,"time":"2024-07-20 18:49:33","name":"C2","adv_raw":"02010617FF000100251505AA00A26C0400410A4101EA0D9400640003094332"}]}}

解决方法

如何根据这个 JSON 字符串,构造 Delphi 的类?靠人眼去读 JSON 然后手写代码,比较累。尤其是里面有很多嵌套。

把这段 JSON 代码丢给 ChatGPT,让它写出对应的 Delphi 类。确实写出来了,但运行结果有问题。

反复和 ChatGPT 拉扯几次后,虽然它每次的回答都不全对,但是,在它东拉西扯的回答里面,逐步发现一些东西,反复做实验,由此增加了对 Delphi 处理 JSON 的了解。

先给出可以运行的代码:

interface

uses
  System.SysUtils,
  System.Classes,
  System.JSON,
  System.Generics.Collections,
  REST.Json.Types,
  REST.Json;



type
  TDevInfo = class
  private
    FAddr: string;
    FRssi: Integer;
    FTime: string;
    FName: string;

    [JSONName('adv_raw')]
    FAdvRaw: string;
  public
    property Addr: string read FAddr write FAddr;
    property Rssi: Integer read FRssi write FRssi;
    property Time: string read FTime write FTime;
    property Name: string read FName write FName;
    property adv_raw: string read FAdvRaw write FAdvRaw;
  end;

  TDevInfos = TArray<TDevInfo>; // array of TDevInfo;

  TData = class
  private
    FFlags: Integer;
    FPktSn: Integer;
    FReportType: string;
    FPktTotal: Integer;
    FPktIndex: Integer;
    FDevTotal: Integer;
    FDevNum: Integer;

    [JSONName('dev_infos')]
    FDevInfos: TDevInfos; //TObjectList<TDevInfo>;
  public
    constructor Create;
    destructor Destroy; override;
    property Flags: Integer read FFlags write FFlags;
    property pkt_sn: Integer read FPktSn write FPktSn;
    property report_type: string read FReportType write FReportType;
    property pkt_total: Integer read FPktTotal write FPktTotal;
    property pkt_index: Integer read FPktIndex write FPktIndex;
    property dev_total: Integer read FDevTotal write FDevTotal;
    property dev_num: Integer read FDevNum write FDevNum;
    property dev_infos: TDevInfos read FDevInfos write FDevInfos;
  end;

  TScanReport = class
  private
    [JSONName('pkt_type')]
    FPktType: string;
    FGwAddr: string;
    FTime: string;
    FData: TData;
  public
    constructor Create;
    destructor Destroy; override;

    class function ParseJSON(const JSONStr: string): TScanReport;

    property PktType: string read FPktType write FPktType;
    property gw_addr: string read FGwAddr write FGwAddr;
    property Time: string read FTime write FTime;
    property Data: TData read FData write FData;
  end;

implementation

{ TScanReport }

constructor TScanReport.Create;
begin
  FData := TData.Create;
end;

destructor TScanReport.Destroy;
begin
  FData.Free;
  inherited;
end;

class function TScanReport.ParseJSON(const JSONStr: string): TScanReport;
begin
  Result := TJson.JsonToObject<TScanReport>(JSONStr);
end;

{ TData }

constructor TData.Create;
begin
  //FDevInfos := TObjectList<TDevInfo>.Create;
end;

destructor TData.Destroy;
begin
  //FDevInfos.Free;
  inherited;
end;

end.

代码的解释和注意事项

1. 一开始 ChatGPT 把 JSON 里面的数组,定义为 TObjectList<T>。但这样做是错误的。错误现象是从 JSON 获得对象没问题,但对象里面的 ObjectList 里面没有内容,其 Count 为 0;这里,必须使用 TArray<> 数组类型,而不能使用 TObjectList<> 来对应 JSON 里面的数组;

2. 解析出来的对象,发现某些字段有值,某些字段没有值。因为 ChatGPT 给出来的代码,属性的名称并没有和 JSON 字符串里面的名称完全一致,所以把字段的属性名称改为和 JSON 字符串里面的名称完全一致(大小写都一样),也不行。最终发现,给每个字段加上类似:[JSONName('dev_infos')] 这样的属性定义,该字段对应的值就有了。

[JSONName('dev_infos')] 这样的属性定义放在类的私有字段定义里面,这个是我这个老程序员不知道的新语法。通过 ChatGPT 学到的。

到此,问题解决。

结论

目前的 ChatGPT 可以帮我们生成 Delphi 代码,节约了手写代码的繁琐。但是,它给出来的代码还是有问题的。之前测试过让它写 Python 代码,写出来的代码运行完全正确。看起来还是 Delphi 不如 Python 热度高,训练永的代码数据比 Python 开源代码少导致。

无论如何,虽然 ChatGPT 写的代码有问题,但仍然提供了思路,在它的代码基础上做一些修改,仍然可以获得能用的代码。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值