我试图捕获以下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中的Memo
或ListBox
中:
代码如下:
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;
我不知道如何解决这个问题或这个错误, 你能帮我吗?
感谢。
答案 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"}]}
如果我按原样运行代码,我会得到以下结果
如果您不介意使用与默认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;
希望它足够清楚:)