2

大家晚上好。

我目前正在开发我的产品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

4

3 回答 3

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;

完成后,请记住 free obj,而不是此处提到的其他变量。

于 2013-02-04T05:20:45.397 回答
2

为了完成,由于问题表明没有DBXJSON跨平台的替代方案,我想指出两个开源替代方案,它们从最初的问题开始出现。

SynCrossPlatformJSON能够通过自定义类型创建无模式对象或数组,将它们序列化和反序列化为 JSON,variant包括后期绑定以访问属性。

对于您的问题,您可以编写:

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)

后期绑定和变体存储允许非常可读的代码。

于 2014-05-19T20:06:47.893 回答
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)。

于 2013-02-04T19:13:15.313 回答