跨平台JSON解析
晚上好。跨平台JSON解析
我目前正在开发我的产品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
相关的电话可能不正确 - 它们只是作为辅助工具。
首先,解析字符串以获取对象。
var
obj: TJsonObject;
obj := TJsonObject.ParseJsonValue(SInput) as TJsonObject;
这给了你一个具有三个属性,响应,结果和味精的对象。尽管ParseJsonValue
是TJsonObject
的一种方法,并且您的特定字符串输入恰好代表对象值,但它可以根据给定的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
,但这里所说的不是其他变量,当您完成。
这仍然有一些问题。 'TJsonValue'没有'.get'例程(我也尝试过'TJsonObject',但是后来在代码中导致问题)。我还对'响应'和'ids'是什么类型(sidenote'ids'应该读作为引用JSON的'ips')的问题感到困惑。我设法构建了35行长的解决方案 - 尽管没有输出到动态数组(但直接输出到备忘录),但您的解决方案意味着它应该更短。 –
我已经修复了ids/ips的错误,并且根据它们在赋值过程中投到了什么类型,明确了变量的类型。由于缺乏细节,我无法帮助您解决您提到的其他问题。你在做什么,你认为你不应该这样做? –
感谢那个Rob。我将你的答案标记为解决方案,因为它使我足够接近以便能够从那里弄清楚(一旦类型已被澄清)。我将很快发布我的解决方案作为答案。 –
感谢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
)。
为了完成,由于该问题表明除了跨平台的DBXJSON
没有其他选择,我想指出两个开源替代方案,这是自最初的问题以来出现的。
- XSuperObject有一个非常接近SuperObject的API,但是是跨平台的;
- 我们的SynCrossPlatformJSON.pas设备比
DBXJSON
和XSuperObject
更轻,速度更快。
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)
后期绑定和变型存储允许非常可读的代码。
这个问题清楚地要求使用DBXJSON的解决方案:“我想使用DBXJSON **解决我的问题的最基本的解决方案**”。我不知道如何为您的单位发布广告和使用它的来源是对这个问题的答案。你能澄清这是如何解决这个问题**使用DBXJSON **? –
因为他无法找到替代品。至少有xsuperobject和我们的单位。 –
然后你简单地决定忽略具体的问题,这是如何做到这一点**使用DBXJSON **?一个问题要求提供工具/图书馆的建议将会成为焦点,但这个问题并没有这么做 - 关于这里提到的工具的相当清楚。 “如何修理我的保时捷?好吧,如果你有宝马,你可以...”不是一个合适的答案。 –
SuperObject只是文本处理。我看不出它是如何不适用于所有平台的。 –
SuperObject使用'Windows'和'WinSock'单元,以及大量使用仅限Windows的例程的程序。它对FPC和UNIX有一些IFDEFS,但没有一个用于MACOS。它深深嵌入代码中。 –
够公平的。看起来像一个穷人做,但。 –