首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将JSON解析为TListBox

将JSON解析为TListBox
EN

Stack Overflow用户
提问于 2012-07-16 19:47:36
回答 2查看 12K关注 0票数 8

晚上好伙计们!

我目前正在尝试为桌面组装一个CloudFlare客户端。我已经连接到他们的API,并使用POST请求成功地检索了JSON结果(其结果已经输出到TMemo中)。现在,我希望将这些结果解析为一个TListBox (例如,请参阅粗体区域)。这个项目是用Firemonkey设计的。

下面是带有一些示例内容的响应的格式化布局;

代码语言:javascript
复制
{
 - response: {
   |- ips: [
      |- {
         ip: "xxx.xxx.xxx.xxx",
         classification: "threat",
         hits: xx,
         latitude: null,
         longitude: null,
         zone_name: "domain-example1"
         },
       - {
         ip: "yyy.yyy.yyy.yyy",
         classification: "robot",
         hits: yy,
         latitude: null,
         longitude: null,
         zone_name: "domain-example2"
         }
       ]
   }
  result : "success",
  msg: null
}

我尝试过几个不同的组件-- SuperObjectPaweł Głowacki's JSON Designtime ParserTiny-JSONLKJSON和内置于DBXJSON中的组件。但是,我完全没有使用JSON的经验,而且我似乎找不到我可以开始学习的最基本的示例。它们中的许多都显示了样本数据,但我尝试过的所有数据似乎都不像我预期的那样起作用,这很可能是因为我误解了它们。我假设组件可以工作,所以我需要开始时的指导。

ips“数组”中有成百上千的结果(如果这不正确,我会假设它是一个数组,但同样,我对JSON完全陌生)。

我真正要寻找的是一些非常基本的示例代码,我可以从这些代码中构建(以及它用于解析的组件等等)。

例如,如果我想从JSON结果中获取每个ip TListBox ,并将其作为一个单独的项放入TListBox(使用 TListBox.add 方法),那么我将如何实现?

当我说ip时,我指的是值(在上面格式化的布局中,这将是xxx.xxx.xxx.xxxyyy.yyy.yyy.yyy)。

另外,如果我想找一张“唱片”(?)通过它的IP从JSON的结果,并输出数据到一个delphi数组-例如;

代码语言:javascript
复制
Result : Array of String = ['"xxx.xxx.xxx.xxx"','"threat"','xx','null','null','"domain-example1"'];

用JSON可以吗?(如果这是一个单独的问题或过于无关的问题,请随意编辑,而不是将问题作为一个整体关闭)。

我最近接触到的不仅仅是ip,还有一个独立的TListItem中的其他数据段(即responseipsipclassificationxxx.xxx.xxx.xxx和其他所有东西都有它自己的项,以及每个非空项之间的几个空项)。

我相信这是非常简单的,但是关于JSON的信息太多了,对于刚开始使用JSON格式的人来说,这有点让人难以接受。

祝你好运斯科特·普里查德。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-07-16 23:01:38

一旦您理解了基本概念,JSON就非常简单和容易理解。看看http://json.org,它解释了一些事情。

在JSON中有4个基本概念:

值是任何JSON元素:基本字符串或数字、数组或对象。(除了一对以外,任何东西都不行。)

数组应该是一个熟悉的概念:一个有序的值列表。与Delphi数组的主要区别在于,JSON数组没有为元素定义的类型;它们只是“JSON值的数组”。

一对是键值对.键可以是字符串或数字,值可以是任何JSON值。

对象是JSON对的关联映射。您可以将它从概念上看作是一个TDictionary<string, JSON value>

因此,如果我想获取这样的JSON数据数组,并将其放入TListBox中,我将执行类似的操作(DBXJSON示例,警告:未测试):

代码语言:javascript
复制
procedure TMyForm.LoadListBox(response: TJSONObject);
var
  i: integer;
  ips: TJSONArray;
  ip: TJSONObject;
  pair: TJSONPair;
begin
  ListBox.Clear;
  pair := response.Get('ips');
  if pair = nil then
    Exit;
  ips := pair.value as TJSONArray;
  for i := 0 to ips.size - 1 do
  begin
    ip := ips.Get(i) as TJSONObject;
    pair := ip.Get('ip');
    if pair = nil then
      ListBox.AddItem('???', ip.Clone)
    else ListBox.AddItem(pair.JsonString, ip.Clone);
  end;
end;

然后,您有一个IP地址列表,以及包含如果用户选择一个完整记录的关联对象。(如果要将每个记录的全部内容放入list控件,请查看TListView。它在这方面比TListBox更有效。)

如果要构建包含所有值的字符串数组,请执行如下操作:

代码语言:javascript
复制
function JsonObjToStringArray(obj: TJsonObject): TArray<string>;
var
  i: integer;
begin
  SetLength(result, obj.Size);
  for i := 0 to obj.Size - 1 do
    result[i] := obj.Get(i).JsonValue.ToString;
end;

当然,这都只是示例代码,但是它应该为您提供一些可构建的东西。

票数 8
EN

Stack Overflow用户

发布于 2012-07-17 17:55:14

EDIT2: AV非常容易修复。

编辑:在进一步检查我自己的代码之后,我意识到它会导致大量内存泄漏。然而,我已经切换到SuperObject,并发现同样的结果可以在两行代码中实现,只有两个变量,没有内存泄漏;

代码语言:javascript
复制
Procedure ParseIPs;
  ISO : ISuperObject;
  MyItem : ISuperObject;
begin
  ISO := SO(RetrievedJSON);
  for MyItem in ISO['response.ips'] do Memo2.Lines.Add(MyItem.S['ip']);
end;

RetrievedJSON只是一个包含未解析的明文JSON的string (即不是JSONString,而是实际的字符串)。

为了保持连续性,我把原始代码留在了下面。

在梅森惠勒的帮助下,在较早的答案中,以及question 9608794上的"teran“提供的答案,我成功地构建了下面的解析,以解析到我需要访问的实际级别(即包含数据的”数组“),然后将带有特定JSONString.Value的所有项目输出到一个列表框中(在下面的示例中名为LB1 );

代码语言:javascript
复制
Procedure ParseIP;
var
  o, Jso, OriginalObject : TJSONObject;
  ThePair, JsPair : TJSONPair;
  TheVal, jsv : TJSONValue;
  jsArr : TJsonArray;
  StrL1 : String;
  i, num : Integer;
begin
  num := 0;
  o := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(Memo1.Text), 0) as TJSONObject;
  ThePair := o.Get('response');
  TheVal := ThePair.JsonValue;
  STRL1 := TheVal.ToString;
  JSV := TJSONObject.ParseJSONValue(STRL1);
  OriginalObject := JSV as TJSONObject;
  JSPair := OriginalObject.Get('ips');
  JSARR := JSPair.JsonValue as TJSONArray;
  for i := 0 to JsArr.Size-1 do
    begin
      JSO := JSArr.Get(i) as TJSONObject;
      for JSPAIR in JSO do
        begin
        num := num+1;
          if JSPAIR.JsonString.Value = 'ip' then
          begin
            LB1.Items.Add(JSPair.JsonValue.Value);
          end
          else null;
        end;
    end;
    ShowMessage('Items in listbox: ' + IntToStr(LB1.Items.Count));
    ShowMessage('Items in JSON: ' + IntToStr(num div JSO.Size));
    Jsv.Free;
end;

虽然这是一种非常全面的方法,但它允许我查看每个单独的步骤,查看它在JSON中的迭代位置,并非常容易地将其转换为一个函数,在这个函数中,我可以根据多个条件之一输出任何数据。为了验证我得到了正确的项目数,我在末尾添加了两个ShowMessage例程;一个用于列表框中的项,一个用于解析的"ip“数据实例数。

这段代码在Fire猴子中使用CloudFlare addition结果进行了专门测试,这些结果被输出到TMemo中,与检索它们完全一样(当然是在&calls_left&a=zone_ips&class=t&geo=1 API调用中,当然是附加了zonetokenemail )。修改它以处理来自其他API调用的其他结果也应该相对容易一些。

为了澄清,我确实尝试过Mason的代码,但不幸的是,我无法让它工作。然而,我暂时接受了他的回答,因为他对基本知识所作的解释是值得的,并帮助我找到了一个最终的解决方案,并想出了一些我可以从中建立起来并教会自己的东西。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11511488

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档