APIから取得したJSONから特定の値を取得する方法について

解決


Hide  2023-04-05 04:46:12  No: 150927  IP: 192.*.*.*

環境はDelphi11.3 Enterpriseで、FMXのTRESTRequestで、駅すぱあとのAPI(駅名=橋)を呼び出し、
結果をTRESTResponseで受け取っています。JSONは次の通りです。
{
    "ResultSet": {
        "apiVersion": "1.27.0.0",
        "max": "1",
        "offset": "1",
        "engineVersion": "202304_03a",
        "Point": {
            "Station": {
                "code": "23281",
                "Name": "橋本(神奈川県)",
                "Type": "train",
                "Yomi": "はしもと"
            },
            "Prefecture": {
                "code": "14",
                "Name": "神奈川県"
            },
            "GeoPoint": {
                "longi": "139.20.51.0",
                "lati": "35.35.30.0",
                "longi_d": "139.3475",
                "lati_d": "35.591667",
                "gcs": "tokyo"
            }
        }
    }
}

※検索結果が複数件ヒットする場合は、上記のJSONのPointより下(Stationから)がネストされます

受け取ったJSONから必要な情報はNameの値だけなので、次の通りコーディングしました。
procedure TForm1.Analize(res: TRESTResponse);
var
  JSONObj: TJSONObject;
  PointArray: TJSONArray;
  staName: String;
begin
  JSONObj := res.JSONValue as TJSONObject;
  PointArray := (JSONObj.GetValue('ResultSet') as TJSONObject).GetValue('Point') as TJSONArray;

  for var i := 0 to PointArray.Count - 1 do
  begin
    staName := PointArray.Items[i].GetValue<TJSONObject>('Station').GetValue('Name').Value;
    ShowMessage(staName);
  end;
end;

これを実行しますと、PointArrayを取得するところで、EInvalidCast例外が発生してしまいます。
但し、検索結果が複数件になる場合は、例外は発生しません。
何か誤っている様でしたら理由を教えて頂けませんでしょうか。

尚、RESTデバッガを使用し、JSONルートにResultSet.Pointを指定すると、結果が1件でも複数件でも
正しく取得されます。

編集 削除
mam  2023-04-05 07:01:35  No: 150928  IP: 192.*.*.*

Pointが配列か配列でないかを確認して分岐処理すれば良いのかもです。

procedure TForm1.Button1Click(Sender: TObject);
var jv1:TJSONValue;
    jv2:TJSONValue;
    st:String;
    i:Integer;
begin
  jv1:=TJSONObject.ParseJSONValue(Memo1.Lines.Text) as TJsonValue;
  jv1:=jv1.GetValue<TJsonValue>('ResultSet');
  jv1:=jv1.GetValue<TJsonValue>('Point');
  if jv1 is TJSONArray then //ここで配列かどうかを判断
  begin
    for i := 0 to TJsonArray(jv1).Count-1 do
    begin
      jv2:=TJsonArray(jv1).Items[i];
      jv2:=jv2.GetValue<TJSONValue>('Station');
      st:=jv2.GetValue<String>('Name');
      showmessage(st);
    end;
  end
  else
  begin
    jv1:=jv1.GetValue<TJsonObject>('Station');
    st:=jv1.GetValue<String>('Name');
    showmessage(st);
  end;
end;

はずしていたらすいません。

編集 削除
Hide  2023-04-05 07:58:04  No: 150929  IP: 192.*.*.*

mamさん、有難うございます。
ご提示頂いた通りのコードで上手く取得できました。
配列か否かを判定するところがポイントだったのですね。
大変勉強になりました。

編集 削除