8

こんばんは!

CloudFlare現在、デスクトップ用のクライアントをまとめようとしています。私は彼らの API に接続し、POST 要求で JSON の結果を正常に取得しました (その結果は に出力されていますTMemo)。これらの結果を に解析したいと考えていますTListBox(例として太字の領域を参照してください)。プロジェクトは で設計されていFiremonkeyます。

いくつかのサンプル コンテンツを含む、書式設定された応答のレイアウトを次に示します。

{
 - 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 の JSON Designtime ParserTiny-JSONLKJSON 、および組み込みの DBXJSON など、いくつかの異なるコンポーネントを試しました。ただし、JSON の経験がまったくなく、開始できる最も基本的な例を見つけることができないようです。それらの多くはサンプルデータを示していますが、私が試したものはすべて、おそらく私がそれらを誤解しているため、期待どおりに機能していないようです. コンポーネントは機能すると思いますので、開始するためのガイダンスが必要です。

「配列」には数百、多くの場合数千の結果がありますips(それが正しくない場合は申し訳ありません。配列として知られていると思いますが、JSONはまったく初めてです)。

私が本当に探しているのは、(解析などに使用するコンポーネントとともに)構築できる非常に基本的なサンプルコードです。

たとえばip、JSON の結果からすべてを取得し、それぞれを別の項目としてTListBox(TListBox.addメソッドを使用して) に入れたい場合、これを達成するにはどうすればよいでしょうか?

私が言うときip、私は値を意味します (上記のフォーマットされたレイアウトでは、これはxxx.xxx.xxx.xxxまたはになりますyyy.yyy.yyy.yyy)。

さらに、JSON の結果から IP で「レコード」(?) を検索し、データを Delphi 配列に出力したい場合は、次のようにします。

Result : Array of String = ['"xxx.xxx.xxx.xxx"','"threat"','xx','null','null','"domain-example1"'];

JSONでそれは可能ですか?(これが別の質問であるか、あまりにも無関係であると見なされる場合は、質問全体を閉じるのではなく、自由に編集してください)。

これに最も近いものには、IPだけでなく、他のすべてのデータが別々にありましたTListItem(つまり、、、、、および他のすべてには独自のアイテムがあり、空でない各アイテムの間にいくつかの空のアイテムがありました)。responseipsipclassificationxxx.xxx.xxx.xxx

実行するのは非常に簡単だと思いますが、JSON には非常に多くの情報があるため、この形式に慣れていない人にとっては少し圧倒されます。

よろしく、スコット・プリチャード。

4

2 に答える 2

8

JSON は非常にシンプルで、基本的な概念を理解すれば簡単に理解できます。http://json.orgを見てください。そこで説明されています。

JSON には 4 つの基本概念があります。

は任意の JSON 要素(基本的な文字列または数値、配列、またはオブジェクト) です。(ペア以外)

配列はおなじみの概念である必要があります: 値の順序付きリストです。Delphi 配列との主な違いは、JSON 配列には要素の型が定義されていないことです。それらは単に「JSON 値の配列」です。

ペアはキーと値のペアです。キーは文字列または数値にすることができ、値は任意の JSON 値にすることができます。

オブジェクトは、JSON ペアの連想マップです。概念的には と考えることができますTDictionary<string, JSON value>

したがって、そのようなデータの JSON 配列を取得して TListBox に入れたい場合は、次のようにします (DBXJSON の例、警告: テストされていません)。

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 アドレスのリストと、ユーザーが選択した場合に取得できる完全なレコードを含む関連オブジェクトがあります。(各レコードの内容全体をリスト コントロールに入れたい場合は、 を参照してくださいTListView。それよりもうまく機能TListBoxします。)

すべての値を含む文字列の配列を作成する場合は、次のようにします。

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;

もちろん、これはすべて単なるサンプル コードですが、これを基に何かを構築する必要があります。

于 2012-07-16T23:01:38.357 に答える
1

EDIT2: AV 非常に簡単に修正。

編集:自分のコードをさらに調べたところ、大量のメモリ リークが発生することがわかりました。ただし、その後切り替えてSuperObject、同じ結果が2つの変数のみでメモリリークのない2行のコードで達成できることがわかりました。

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

RetrievedJSONstringは、解析されていないプレーンテキストの JSON を含む単純な です(つまり、 ではJSONStringなく、実際の文字列です)。

継続性のために、元のコードを下に残しました。


以前の回答での Mason Wheeler の支援と、質問 9608794で「teran」によって提供された回答により、アクセスする必要がある実際のレベル (つまり、データを含む「配列」) まで解析するために、以下を正常に構築しました。 、次に特定のすべてのアイテムをJSONString.Valueリストボックスに出力します(LB1以下のサンプルで名前が付けられています);

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 のどこを繰り返し処理しているかを非常に簡単に確認し、任意の部分を出力できる関数に変更することができます。または複数の基準の 1 つに基づく結果としてのデータの範囲。正しい数のアイテムを取得したことを確認するためにShowMessage、最後に 2 つのルーチンを追加しました。1 つはリストボックス内の項目用で、もう 1 つは解析していた「ip」データのインスタンス数用です。

このコードは、CloudFlare API JSON の結果を使用して Firemonkey で特にテストされ、TMemo取得されたとおりに出力されました ( &calls_left&a=zone_ips&class=t&geo=1API 呼び出しで、もちろん、あなたのが追加されzonetokenさらにemail追加されました)。他の多数の API 呼び出しからの他の結果と連携するように変更することも比較的簡単なはずです。

明確にするために、メイソンのコードを試しましたが、残念ながら動作しませんでした。しかし、彼が基本について行った説明はそれに値するものであり、最終的な解決策にたどり着き、そこから構築して自分で学ぶことができるものを思いつくのを助けたという理由で、当分の間彼の答えを受け入れました.

于 2012-07-17T17:55:14.580 に答える