4

我最近在解析 JSON 时碰壁了。你看,在使用 CloudFlare 客户端接口 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>是一个数值)。因此,我不能依赖返回的已知数据类型。

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

4

2 回答 2

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
于 2012-07-22T09:29:54.133 回答
1

解决这个问题的技巧在某种程度上是这种“限制”的粗略解决方法。可能还有其他方法——在 SuperObject 中甚至可能有一个函数来实现这一点——但这是大多数新编码人员可能会感到满意的方法(无论是 Delphi 新手、Coding 新手还是 SuperObject 新手)。它利用StringReplace函数替换“.”。具有对字段名称更友好的字符的实例(在这种情况下,我使用*)。正如我所说,这是一种粗略的方法,并且可能有一种更简单的方法,但是新编码人员可以从中学习的简单解决方案具有它的位置。

细节

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

MyJSON将已经检索到的 JSON 表示为string. 这可以是TMemo.text,TEdit.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 中的布尔值、整数还是字符串。如您所见,在完美实现目标的同时非常容易理解。潜在的问题是,如果结果中有 a .,那么您的输出值将有 a *。你可以很容易地用 包装结果StringReplace,像这样;

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

从此展开

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

当然欢迎任何其他答案!

于 2012-07-21T23:03:27.653 回答