跨平台JSON解析

跨平台JSON解析,json,delphi,delphi-xe3,firemonkey-fm2,Json,Delphi,Delphi Xe3,Firemonkey Fm2,大家晚上好 我目前正在开发我的产品的跨平台兼容版本。我面临的问题是,Firemonkey仍然不能跨平台兼容。当然,我在产品的原始版本中使用了它,但现在我想创建一个跨平台版本,而不是仅限于Windows,我发现这是一个麻烦 DBXJSON是我经过数小时的研究后找到的唯一跨平台解决方案,但事实证明,尝试和处理这一问题令人沮丧。我找到的大多数例子要么不适用于我的情况,要么太复杂,无法从中找到有用的东西。有很多讨论,但我只是在努力掌握SuperObject的简单任务。今天晚上我花了大部分时间试图找到一些

大家晚上好

我目前正在开发我的产品的跨平台兼容版本。我面临的问题是,Firemonkey仍然不能跨平台兼容。当然,我在产品的原始版本中使用了它,但现在我想创建一个跨平台版本,而不是仅限于Windows,我发现这是一个麻烦

DBXJSON
是我经过数小时的研究后找到的唯一跨平台解决方案,但事实证明,尝试和处理这一问题令人沮丧。我找到的大多数例子要么不适用于我的情况,要么太复杂,无法从中找到有用的东西。有很多讨论,但我只是在努力掌握SuperObject的简单任务。今天晚上我花了大部分时间试图找到一些可以用来建造的东西,但我所做的一切都让我回到了起点

理想情况下,我希望修复SuperObject,但我缺乏深入了解,无法使其与OSX跨平台兼容(并为移动工作室做好准备)。我欢迎任何关于这方面的建议,但我想没有人有时间完成这么大的任务,看起来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
相关的调用可能是不正确的-它们只是作为一种帮助。

首先,解析字符串以获得一个对象

var
  obj: TJsonObject;

obj := TJsonObject.ParseJsonValue(SInput) as TJsonObject;
这将为您提供一个具有三个属性的对象:response、result和msg。尽管
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,但不要释放这里提到的其他变量。

感谢来自的帮助,我成功地构建了解决问题的解决方案

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
)。

为了完成,因为问题指出对于跨平台而言,除了
DBXJSON
之外没有其他选择,我想指出两个开源的替代方案,它们出现在最初的问题之后

  • API非常接近,但是跨平台的
  • 我们的单元比
    DBXJSON
    XSuperObject
    更轻,速度更快
SynCrossPlatformJSON
能够创建无模式的对象或数组,通过自定义的
变量
类型(包括访问属性的后期绑定)将其序列化并取消序列化为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)

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

SuperObject只是文本处理。我看不出它怎么会不适用于所有的平台。SubObject使用的是
Windows
WinSock
单元,以及大量使用Windows专用例程的过程。它确实有一些用于FPC和UNIX的IFDEF,但没有一个用于MACOS。它深深地嵌入到代码中,这很公平。不过,这似乎是一个糟糕的做法。看看JSON单元可以“单独”使用。我确实研究了dwscript,但与SuperObject一样,
dwsJSON.pas
也引入了一些与OS X不兼容的其他单元(例如,
dwsXPlatform
TJsonValue
没有
.get
例程(我也尝试了
TJsonObject
,但这会导致代码中出现问题)。我还对
response
ids
是什么类型感到困惑(旁注
ids
应该读
ips
,作为问题中JSON的参考)。我成功地构建了一个35行长的解决方案——虽然没有将其输出到动态数组(而是直接输出到备忘录),但您的解决方案意味着它应该更短。我已经修复了ID/ips错误,并根据赋值期间强制转换的类型,明确了变量的类型。由于缺乏细节,我无法帮助解决你提到的其他问题。你在做什么你认为不该做的事?谢谢你,罗布。我将您的答案标记为解决方案,因为它使我能够从中找到答案(一旦类型得到澄清)。我将很快发布我的解决方案作为答案。这个问题显然要求使用DBXJSON的解决方案:“我想要使用DBXJSON的最基本解决方案来解决我的问题”。我不确定为你的单位和使用它的来源发布广告是如何回答这个问题的。您能否澄清一下,这是如何使用DBXJSON解决问题的?因为他无法找到替代方案。至少有xsuperobject和我们的单位。然后你决定