DelphiでJSONの第2階層以降や配列化されたデータを取得する方法を紹介します。
TJsonSerializer
ここではTJsonSerializerの利用方法を紹介します。
使用例を示した方がわかりやすいと思いますので、無料で為替レート情報を提供しているGMOコインさんの為替レート取得APIで得られるJsonからデータを取リ出すプログラムを示します。
GMOコインの為替レート取得API
こちらの紹介記事で存在を知りました。GMOコインは口座開設をしなくても無料でAPIが利用出来て、APIキーが必要ないPublic APIとなっているとのことです。以前紹介したことのあるExchangeRatesのAPIは無料で利用できるAPIはHTTP接続のみでHTTPS接続は有料となるため、Adroidアプリでの利用を念頭にGMOコインの為替レート取得APIを試してみました。
APIキーが必要ないため、URLを入れるだけで簡単にJsonを確認できます。
最新レート取得API(ticker)のURLはhttps://forex-api.coin.z.com/public/v1/tickerです。Jsonを見やすくするとこんな感じです。
Jsonの構造
このようにJsonを見やすくすると、あとでレコードを作成する際に便利です
{
"status": "0",
"data": [
{
"symbol":"USD_JPY",
"ask":"149.355",
"bid":"149.263",
"timestamp":"2025-03-22T07:18:21.935993Z",
"status":"CLOSE"
}
{
"symbol":"EUR_JPY",
"ask":"161.558",
"bid":"161.445",
....
....
}
....
]
"responsetime":"2025-03-22T07:18:22.012Z"
}
今回は、USD_JPY(ドル円)のbid(売値)の値を取得することを目的にします。
Jsonの取得から文字列に変換するところまで
TJsonSerializerでは文字列にしたJsonが必要になります
var
HTTPResponse: IHTTPResponse;
JSon : TStringStream;
JsonText: String;
HTTPClient: TNetHTTPClient;
Request : TNetHTTPRequest;
....
begin
Json:= TStringStream.Create('', TEncoding.UTF8);
Request := TNetHTTPRequest.Create(nil);
HTTPClient:= TNetHTTPClient.Create(Request);
try
HTTPClient.ContentType := 'application/json';
HTTPClient.Accept := 'application/json';
HTTPClient.ConnectionTimeout := 20000;
HTTPClient.ResponseTimeout := 20000;
HTTPResponse:= HTTPClient.Get('https://forex-api.coin.z.com/public/v1/ticker',Json);
JsonText:= HTTPResponse.ContentAsString(TEncoding.UTF8);
....
TJsonSerializerで使うレコードの準備
TJsonSerializerではJsonの要素をレコードにして扱います
type
TData = record // dataの要素
symbol:String;
ask: Double;
bid: Double;
timestamp: String;
status: String;
end;
TRoot = record // JSON 全体
status: integer;
data: TArray<TData>; // TData の配列
end;
var
....
USD_JPY(ドル円)のbid(売値)の値を取得
TJsonSerializerでJsonの要素を取り出す用例を示します
var
....
JsonSerial : TJsonSerializer;
Root : TRoot;
LYPD : Double;
begin
....
JsonSerial := TJsonSerializer.Create;
try
Root := JsonSerial.Deserialize<TRoot>(JsonText);
LYPD := Root.data[0].bid; //USD_JPY(ドル円)のbid(売値)の値
finally
JsonSerial.Free;
end;
....
TJsonSerializerを使うとこんな簡単でいいのっていうぐらい、直感的ですごくわかりやすくなりますね。
関数全体
function TFormMain.GetYPD: Double;
type
TData = record // dataの要素
symbol:String;
ask: Double;
bid: Double;
timestamp: String;
status: String;
end;
TRoot = record // JSON 全体
status: integer;
data: TArray<TData>; // TData の配列
end;
var
HTTPResponse: IHTTPResponse;
JSon : TStringStream;
JsonText: String;
HTTPClient: TNetHTTPClient;
Request : TNetHTTPRequest;
JsonSerial : TJsonSerializer;
Root : TRoot;
LYPD : Double;
begin
Json:= TStringStream.Create('', TEncoding.UTF8);
Request := TNetHTTPRequest.Create(nil);
HTTPClient:= TNetHTTPClient.Create(Request);
try
HTTPClient.ContentType := 'application/json';
HTTPClient.Accept := 'application/json';
HTTPClient.ConnectionTimeout := 20000;
HTTPClient.ResponseTimeout := 20000;
HTTPResponse:= HTTPClient.Get('https://forex-api.coin.z.com/public/v1/ticker',Json);
JsonText:= HTTPResponse.ContentAsString(TEncoding.UTF8);
JsonSerial := TJsonSerializer.Create;
try
Root := JsonSerial.Deserialize<TRoot>(JsonText);
LYPD := Root.data[0].bid;
finally
JsonSerial.Free;
end;
except
on E:Exception do
begin
LYPD := 0;
end;
end;
Result:= LYPD;
HTTPClient.Free;
Request.Free;
Json.Free;
end;
uses
System.Net.HttpClient, System.Net.HttpClientComponent,
System.JSON.Serializers
漏れがあったらごめんなさい🙇
Delphi12(FMX)で作成し、Windows11とAndroid9,12で動作を確認。
Android苦労話
VCLのRestコンポーネントを使って取得したExchangeRatesのAPIのJsonを解析するWindowsアプリをAndroidでも使えるようにFMXに移植しようとしたことが、今回の記事のネタとなったきっかけでした。
Androidで発生したエラーと原因
Windowsで動作確認をする限り、VCLからFMXへの移植は完璧に思えました。ところが、Androidで実行するとJsonを取得する過程で以下の4つのエラーが発生しました。
プロジェクト ***.apk は例外クラス EJNIException (メッセージ 'java.io.IOException: Cleartext HTTP traffic to api.exchangeratesapi.io not permitted')を送出しました。
プロジェクト ***.apk は例外クラス ENetHTTPCertificateException (メッセージ 'java.io.IOException: Cleartext HTTP traffic to api.exchangeratesapi.io not permitted')を送出しました。
プロジェクト ***.apk は例外クラス ENetHTTPCertificateException (メッセージ 'java.io.IOException: Cleartext HTTP traffic to api.exchangeratesapi.io not permitted')を送出しました。
プロジェクト ***.apk は例外クラス ERESTException (メッセージ 'REST 要求が失敗しました: java.io.IOException: Cleartext HTTP traffic to api.exchangeratesapi.io not permitted')を送出しました。
結論としては、Androidのパーミッションの問題だとわかったのですが、最初はコード内のエラーの発生源を突き止めようとして莫大な時間を浪費してしまいました。上記のコードでRestコンポーネントではなく、TNetHTTPClientなどを直接Createして使っているのは、原因追及の過程でRestコンポーネントに疑いを持ってしまったせいです。最終的には上のエラーメッセージの「Cleartext HTTP traffic to — not permitted」の部分に着目して検索したところ、こちらのページからこちらのページにたどり着き、問題点が明らかになりました。
Android(9以降?)ではHTTP接続のAPIは使えない?
らしいので、結局ExchangeRatesの使用はあきらめてHTTPS接続が可能なAPIを探すことにしました。
AndroidManifest.xmlに対する加筆
も必要みたいです。先ほど紹介したこちらのページのOption2とOption3の部分が参考になります。Option2のnetwork_security_config.xmlは
\dprojのあるフォルダ\res\xml\ に作成して念のために「配置マネージャ」に登録しました。リモートパスはres\xml\としました。
また、network_security_config.xml内のapi.example.com(to be adjusted)の部分は、forex-api.coin.z.comとしました。
GMOコインさんの為替レート取得APIのメリット
無料でHTTPS接続が可能な上に、APIキーがいらなというのはいいですね。ExchangeRatesの時はユーザーさんに自分でAPIキーを取得してもらい、APIキーをiniファイルに保存するようにしていたのですが、これらが不要になるメリットは大きいです。GMOコインさん、ありがとうございます!いつか暗号資産やFXに手を出すときがきたら利用させてもらいます🙏
便利すぎるTJsonSerializer
ExchangeRatesが使えなくなったので、GMOコイン用のJson解析コードを組むことが必要になったのですが、この記事を見つけたおかげでTJsonSerializerを知ることができました。Jsonを意識することなく、Delphiで使い慣れたオブジェクトのように扱えるのが本当に便利です。ExchangeRatesが使えないことがわかったときはショックでしたが、そのせいでGMOコインのAPIとTJsonSerializerに出会えたのは怪我の功名でした。
Android版「楽天お知らせメールを家計簿スプレッドシートに貼り付けるためのアプリ」
謎のエラーが発生したときと、ExchangeRatesが使えないとわかったときは、米国株配当金の入金のお知らせメールの解析機能の実装はあきらめるしかないと思ったのですが、結果的にいままで以上に使い勝手のいいアプリになりそうです。5月中には公開したいですね。