我最近在解析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>
是数值)。因此,我不能依赖于返回的已知数据类型。
然而,主要问题是,由于字段名称中的点,尝试从此字段读取值显然会失败。
答案 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.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中的布尔值,整数还是字符串。如您所见,在完美实现目标的同时,它非常容易理解。潜在的问题是如果结果中包含.
,那么您的输出值就会有*
。你可以很容易地用StringReplace
包装结果,就像这样;
StringReplace(iso.s['response'+'.'+FmIP],'*','.',[rfReplaceAll]);
从此扩展
您可以使用Pos
或AnsiPos
来查找IP本身的位置。从中扩展,获得最终字符的位置相对容易,因此,您可以找到可在此特定情况之外使用的函数。但是,讨论这个问题会更好地作为一个通用的“有用的字符串函数”答案,而不是这个特定的讨论。
当然欢迎任何其他答案!