首页 > 解决方案 > 将 JSON 反序列化为类型对象数组(Delphi 11)

问题描述

我正在尝试反序列化来自 Web 服务的 JSON 响应。响应采用类型良好的对象数组的形式。例如,我使用的是 songster.com。

在下面的(摘录)代码中,显然TSongsterResponse是不正确的,因为我得到了一个集合。但两者都array of TSongsterResponse不会TSongsterList编译。

interface

type
  TSongsterResponse = class
    public
      id: integer;
      title: string;
  end;

type TSongsterList = array of TSongsterResponse;

implementation

procedure Sample(AJson: string);
begin
  // What goes here to get an array of TSongsterResponse?
  FSomething :=   TJson.JsonToObject<?????>(RESTResponse1.Content);
end;

标签: jsondelphi

解决方案


TJson.JsonToObject(),顾名思义,需要对象类型,而不是数组类型。它有一个 Generic 约束class, constructor,这意味着它必须能够Create反序列化成一个对象。它不能反序列化不在 JSON 对象内部的 JSON 数组。

您可以尝试使用 包装RESTResponse1.Content'{...}'否则您可能只需要求助于使用并自己手动TJSONObject.ParseJSONValue()构建(请参阅Delphi 解析 JSON 数组或数组)。TSongsterList

查看正在解析的实际 JSON 会有所帮助,但没有什么能阻止您定义自己的类类型以将 JSON 值复制到其中。例如:

interface

type
  TSongsterResponse = class
  public
    id: integer;
    title: string;
  end;

  TSongsterList = array of TSongsterResponse;

implementation

uses
  System.JSON;

var
  FSomething: TSongsterList;

procedure Sample(AJson: string);
var
  Value: TJSONValue;
  Arr: TJSONArray;
  Obj: TJSONObject;
  Song: TSongsterResponse;
  I: Integer;
begin
  Value := TJSONObject.ParseJSONValue(AJson);
  if Value = nil then Exit;
  try
    Arr := Value as TJSONArray;
    SetLength(FSomething, Arr.Count);
    for I := 0 to Arr.Count-1 do
    begin
      Obj := Arr[I] as TJSONObject;
      Song := TSongsterResponse.Create;
      try
        Song.id := (Obj.GetValue('id') as TJSONNumber).AsInt;
        Song.title := Obj.GetValue('title').Value;
        FSomething[I] := Song;
      except
        Song.Free;
        raise;
      end;
    end;
  finally
    Value.Free;
  end;
  // use FSomething as needed...
end;
...
Sample(RESTResponse1.Content);

话虽如此,请注意它TRESTResponse有一个JSONValue属性可以为您解析接收到的 JSON 内容,例如:

interface

type
  TSongsterResponse = class
  public
    id: integer;
    title: string;
  end;

  TSongsterList = array of TSongsterResponse;

implementation

uses
  System.JSON;

var
  FSomething: TSongsterList;

procedure Sample(AJson: TJSONValue);
var
  Arr: TJSONArray;
  ...
begin
  Arr := AJson as TJSONArray;
  // process Arr same as above...
  // use FSomething as needed...
end;
...
Sample(RESTResponse1.JSONValue);

推荐阅读