Json 数组到 ListBox/Memo in Delphi xe7

Json Array into ListBox/Memo in Delphi xe7

我正在尝试捕获以下 JSON 数组:

[{"name":"Bryan","email":"Bryan@hotmail.com"},
 {"name":"Louis","email":"Louis@hotmail.com"},
 {"name":"Maria","email":"Maria@hotmail.com"},
 {"name":"Test","email":"test@hotmail.com"},
 {"name":"Anthony","email":"anthony@hotmail.com"}]

并将其放入 Delphi 中的 MemoListBox 中: 代码如下:

procedure TForm1.Button1Click(Sender: TObject);
var jv: TJSONValue;
    jo: TJSONObject;
    jp: TJSONPair;
    ja: TJSONArray;
    i: integer;
    j: integer;
begin
    RESTRequest1.Execute;

    jv:=RESTResponse1.JSONValue;


    jo:= TJSONObject.ParseJSONValue(jv.ToString) as TJSONObject;

    try
      for i := 0 to jo.Size - 1 do
      begin
        jp := jo.Get(i);
        if jp.JsonValue is TJSONArray then
        begin
            ja := jp.JsonValue as TJSONArray;
            for j := 0 to ja.Size -1 do
              Memo1.Lines.Add(ja.Get(i).ClassName + ': ' + ja.Get(j).ToString);
        end
        else
          Memo1.Lines.Add(jp.ClassName + ': '+ jp.ToString);

      end;
    finally
      jo.Free;
    end;
end;

当我点击按钮时,我收到以下错误消息:

Invalid class typecast

在调试过程中,以下行有问题: jo:= TJSONObject.ParseJSONValue(jv.ToString) as TJSONObject;

我不知道如何解决这个问题或这个错误, 你能帮帮我吗?

谢谢。

这完全可以通过阅读代码和查看 JSON 来解决。但是,我想向您展示如何调试此类问题,以防您无法通过静态分析解决该问题。当 as 转换失败时,总是因为 as 左侧的对象不是从右侧的类型派生的。下一步总是询问左侧对象的类型是什么。我在上面包含了一个简短的 MCVE 作为演示的方式。

这个程序的输出:

{$APPTYPE CONSOLE}

uses
  System.JSON;

const
  JSON = '[{"name":"Bryan","email":"Bryan@hotmail.com"},' +
         ' {"name":"Louis","email":"Louis@hotmail.com"},' +
         ' {"name":"Maria","email":"Maria@hotmail.com"},' +
         ' {"name":"Test","email":"test@hotmail.com"},' +
         ' {"name":"Anthony","email":"anthony@hotmail.com"}]';

begin
  Writeln(TJSONObject.ParseJSONValue(JSON).ClassName);
end.

TJSONArray

现在,TJSONArray 不派生自 TJSONObject。因此,您的 as 转换会引发运行时错误。如果将 ParseJSONValue 返回的值转换为 TJSONArray,那将会成功。

这是意料之中的,因为您的 JSON 的根是一个数组而不是对象。

您需要修改您的代码,使其不假定根级别始终是一个对象。数组和对象需要不同的行为。

我不确定 TJSONObject 的问题与您发布的字符串有关。
出于某种原因,如果您更改它,它会解析它。

{"Persons":[{"name":"Bryan","email":"Bryan@hotmail.com"},{"name":"Louis","email":"Louis@hotmail.com"},{"name":"Maria","email":"Maria@hotmail.com"},{"name":"Test","email":"test@hotmail.com"},{"name":"Anthony","email":"anthony@hotmail.com"}]}

如果我运行原样的代码,我会得到以下结果

如果您不介意使用与默认 Delphi 单位不同的东西,我建议您使用 superobject (Link here)
superobject 将解析您的 JSON 编辑和发布。

您的代码如下所示:

Const
  MyJSON = '[{"name":"Bryan","email":"Bryan@hotmail.com"},{"name":"Louis","email":"Louis@hotmail.com"},{"name":"Maria","email":"Maria@hotmail.com"},{"name":"Test","email":"test@hotmail.com"},{"name":"Anthony","email":"anthony@hotmail.com"}]';    
procedure ParseJSON;
  var
    obj: ISuperObject;
    Ar: TSuperArray;
    I: integer;
  begin
    obj := SO(MyJSON);
    if obj.IsType(stArray) then
    begin
      Ar := obj.AsArray;
      try
        for I := 0 to Ar.Length-1 do
          L.Add(Ar.O[I].AsString);
      finally
        Ar.Free;
      end;
    end
    else
      L.Add(Obj.AsString);
  end;

结果:

对于 Koul,获取元素名称和值。
就像我说的不是很漂亮的代码但是还可以。

Ar.O[0].AsObject.GetNames.AsArray.S[0]

把它切碎一点。

Ar.O[0] //Get the first element in the array as ISuperObject  
.AsObject //Get it as TSuperTableString
.GetNames //Gets all names in the array, in this case "name" and "email"
.AsArray[0]//Get the first name in the names array.

它将导致 email(名称按 A-Z 排序)

您可以通过调用 GetValues 而不是 GetNames 来对值执行相同的操作。
我认为获得它的最漂亮的方法是多定义 2 倍 TSuperArray

procedure PrintNamesAndValues;
Var
  Ar, ArNames, ArValues:TSuperArray;
  I: Integer;
begin
  Ar := SO(<JSON string>).asArray;  
  ArNames := Ar.O[0].AsObject.GetNames.AsArray;
  ArValues := Ar.O[0].AsObject.GetValues.AsArray;
  For I := 0 to ArNames.Length-1 do
    WriteLn(Format('%s: %s',[ArNames.S[I], ArValues.S[I]]));  
end;

希望一切都足够清楚:)