晚上好。
我目前正在开发我的产品WinFlare的跨平台兼容版本。我面临的问题是SuperObject仍然不与Firemonkey跨平台兼容。无论如何,我在产品的原始版本中使用它,但现在我想创建一个跨平台版本,而不是仅限于Windows,我发现这是一个麻烦。
DBXJSON
是我经过长时间研究后才能找到的唯一跨平台解决方案,但事实证明这是令人沮丧的尝试和处理。我发现的大部分例子都不适用于我的情况,或者它们太复杂,无法从中汲取任何有用的东西。有很多讨论,但我只是在努力去掌握SuperObject这么简单的任务。我今晚花了大部分时间试图找到可以构建的东西,但是我尝试过的所有东西都让我回到原点。
理想情况下,我想修复SuperObject,但我缺乏深入的知识,以使其与OS X跨平台兼容(并为移动工作室做好准备)。我欢迎任何有关这方面的建议,但正如我想象的那样,没有人有时间完成这么大的任务,看起来DBXJSON是我唯一的选择。
我正在处理的JSON布局仍然相同;
{
response: {
ips: [
{
ip: "xxx.xxx.xxx.xxx",
classification: "threat",
hits: xx,
latitude: xx,
longitude: xx,
zone_name: "domain-example1"
},
{
ip: "yyy.yyy.yyy.yyy",
classification: "robot",
hits: yy,
latitude: xx,
longitude: xx,
zone_name: "domain-example2"
}
]
}
result : "success",
msg: null
}
ips
数组中可能有数百个结果。假设我想解析数组中的所有项并提取每个latitude
值。让我们假设一秒钟,我打算将它们输出到一个数组。这是我想要使用的那种代码模板;
procedure ParseJsonArray_Latitude(SInput : String);
var
i : Integer;
JsonArray : TJsonArray;
Begin
// SInput is the retrieved JSON in string format
{ Extract Objects from array }
for i := 0 to JsonArray.Size-1 do
begin
Array_Latitude[i] := JsonArray.Item[i].ToString;
end;
end;
基本上,在{ Extract Objects from array }
的位置,我希望最基本的解决方案使用 DBXJSON 来解决我的问题。显然,我在上面的模板中显示的与JsonArray
相关的电话可能不正确 - 它们只是作为一种帮助。
答案 0 :(得分:3)
首先,解析字符串以获取对象。
var
obj: TJsonObject;
obj := TJsonObject.ParseJsonValue(SInput) as TJsonObject;
它为您提供了一个具有三个属性的对象,响应,结果和消息。虽然ParseJsonValue
是TJsonObject
的方法,并且您的特定字符串输入恰好表示对象值,但它可以返回任何TJsonValue
后代的实例,具体取决于它给出的JSON文本。知道从哪里开始可能是使用DbxJson最难的部分。
接下来,获取响应属性值。
response := obj.Get('response').JsonValue as TJsonObject;
该结果应该是另一个对象,这次使用一个属性ips。获取该属性,该属性应具有值的数组。
ips := response.Get('ips').JsonValue as TJsonArray;
最后,您可以从数组中获取值。看起来你期望值是数字,所以你可以这样投射它们。
for i := 0 to Pred(ips.Size) do
Array_Latitude[i] := (ips.Get(i) as TJsonObject).Get('latitude').JsonValue as TJsonNumber;
当你完成时,请记得免费obj
,而不是这里提到的其他变量。
答案 1 :(得分:2)
完成之后,由于问题表明跨平台没有DBXJSON
的替代方案,我想指出两个开源替代方案,这些方案自最初的问题出现以来。
DBXJSON
和XSuperObject
更轻,速度更快。 SynCrossPlatformJSON
能够创建无架构对象或数组,通过自定义variant
类型将它们序列化并反序列化为JSON,包括后期绑定访问属性。
对于你的问题,你可以写:
var doc: variant;
ips: PJSONVariantData; // direct access to the array
i: integer;
...
doc := JSONVariant(SInput); // parse JSON Input and fill doc custom variant type
if doc.response.result='Success' then // easy late-binding access
begin
ips := JSONVariantData(doc.response.ips); // late-binding access into array
SetLength(Arr_Lat,ips.Count);
for i := 0 to ips.Count-1 do begin
Arr_lat[i] := ips.Values[i].latitude;
Memo1.Lines.add(ips.Values[i].latitude);
end;
end;
... // (nothing to free, since we are using variants for storage)
后期绑定和变体存储允许非常易读的代码。
答案 2 :(得分:0)
感谢Rob Kennedy的帮助,我设法构建了解决问题的解决方案;
var
obj, response, arrayobj : TJSONObject;
ips : TJSONArray;
JResult : TJsonValue;
i : Integer;
Arr_Lat : Array of string;
begin
try
Memo1.Lines.Clear;
obj := TJsonObject.ParseJSONValue(SInput) as TJSONObject;
response := Obj.Get('response').JsonValue as TJSONObject;
ips := response.Get('ips').JsonValue as TJSONArray;
SetLength(Arr_Lat, ips.Size-1);
for i := 0 to ips.Size-1 do
begin
arrayobj := ips.Get(i) as TJSONObject;
JResult := arrayobj.Get('latitude').JsonValue;
Arr_lat[i] := JResult.Value;
Memo1.Lines.Add(JResult.Value);
end;
finally
obj.Free;
end;
这会将结果添加到数组(Arr_Lat
),并将它们输出到备忘录(Memo1
)。