SuperObject - 从带有“。”的字段名解析数据。文字

时间:2012-07-21 23:03:28

标签: json delphi firemonkey cloudflare superobject

我最近在解析JSON时遇到了障碍。您可以看到,在使用CloudFlare Client Interface API时,我想查找特定IP的“威胁评级”。问题在于,由于API的设计,格式是这样的;

{
 response: {
            xxx.xxx.xxx.xxx: <value>,
            calls_left: 299
            },
 result: "success",
 msg: null
}

xxx.xxx.xxx.xxx表示从中检索数据所需的字段名称。马上,你可能会看到我面临的问题;假设解析字符串中的点字符是当前路径中的子级别。

<value>代表IP的实际评级。但是,从它返回的格式和数据类型会有所不同。如果IP不是威胁,或者没有威胁评级,则返回false作为布尔值。在搜索引擎抓取工具上,它将"SE:<var>"(其中<var>是一个数字值)作为字符串返回。在已知威胁上,它返回"BAD:<var>"(其中<var>是数值)。因此,我不能依赖于返回的已知数据类型。

然而,主要问题是,由于字段名称中的点,尝试从此字段读取值显然会失败。

2 个答案:

答案 0 :(得分:7)

不需要黑客攻击。您只需要通过AsObject。然后使用名称(包括嵌入点),而不将其视为路径说明符。

const Line1 = '{'
      + #13#10' response: {'
      + #13#10'            xxx.xxx.xxx.xxx: "somestring",'
      + #13#10'            calls_left: "299"'
      + #13#10'            },'
      + #13#10' result: "success",'
      + #13#10' msg: null'
      + #13#10'}';

var
  super: ISuperObject;
  res: ISuperObject;
begin
  super := SO(Line1);
  res := super.O['response'];

  writeln('S[calls_left''] on res: ', res.S['calls_left']);
  writeln('S[''xxx.xxx.xxx.xxx''] on res: ', res.S['xxx.xxx.xxx.xxx']);

  writeln('Names: ', res.AsObject.GetNames.AsString);
  writeln('Values: ', res.AsObject.GetValues.AsString);

  writeln('S[''xxx.xxx.xxx.xxx''] on res: through AsObject: ',
    res.AsObject.S['xxx.xxx.xxx.xxx']);

给出以下结果:

S[calls_left'] on res: 299
S['xxx.xxx.xxx.xxx'] on res:
Names: ["calls_left","xxx.xxx.xxx.xxx"]
Values: ["299","somestring"]
S['xxx.xxx.xxx.xxx'] on res: through AsObject: somestring

答案 1 :(得分:1)

这方面的诀窍是这种“限制”的粗略解决方法。可能还有其他方法 - 在SuperObject中甚至可能有一个函数来实现这一点 - 但这是大多数新编码员可能会习惯的(Delphi新手,编码新手或SuperObject新手)。它利用StringReplace函数替换“。”具有更多字段名称友好字符的实例(在这种情况下,我使用*)。正如我所说,这是一种粗糙的方法,可能有一种更简单的方法,但是新编码员可以从中学习的简单解决方案就是它的位置。

<强>详情

请注意,此特定示例适用于当前的CloudFlare API,因此建议您进行扩展。它需要SuperObject才能工作。

MyJSON将已检索的JSON表示为string。这可以是TMemo.textTEdit.text,也可以只是标准字符串。

MyIP代表您想要查找的IP。

Function GetValue(MyJson, MyIP : String) : String;
var
  ISO : ISuperObject;
  FmIP, FmJSON : String;
begin  
  FmJSON := StringReplace(MyJSON,'.','*',[rfReplaceAll]);
  FmIP := StringReplace(MyIP,'.','*',[rfReplaceAll]);
  ISO := SO(FmJSON);
  Result := iso.s['response'+'.'+FmIP];
end;

这将以字符串形式返回结果,无论它是JSON中的布尔值,整数还是字符串。如您所见,在完美实现目标的同时,它非常容易理解。潜在的问题是如果结果中包含.,那么您的输出值就会有*。你可以很容易地用StringReplace包装结果,就像这样;

StringReplace(iso.s['response'+'.'+FmIP],'*','.',[rfReplaceAll]);

从此扩展

您可以使用PosAnsiPos来查找IP本身的位置。从中扩展,获得最终字符的位置相对容易,因此,您可以找到可在此特定情况之外使用的函数。但是,讨论这个问题会更好地作为一个通用的“有用的字符串函数”答案,而不是这个特定的讨论。

当然欢迎任何其他答案!