Json Array进入Delphi xe7中的ListBox / Memo

时间:2015-02-12 09:04:03

标签: json delphi 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;

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

  

无效的类别类型

在调试期间,以下行有一个问题: jo:= TJSONObject.ParseJSONValue(jv.ToString) as TJSONObject;

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

感谢。

2 个答案:

答案 0 :(得分:1)

通过阅读代码并查看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的根是一个数组而不是一个对象。

您需要修改代码,以便它不会假定根级别始终是对象。您需要不同的数组和对象行为。

答案 1 :(得分:0)

我不确定您发布的字符串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"}]}

如果我按原样运行代码,我会得到以下结果 enter image description here

如果您不介意使用与默认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;

结果:
enter image description here

对于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;

希望它足够清楚:)