Embarcaderoヘルプのサンプルコード( http://docwiki.embarcadero.com/RADStudio/XE5/en/JSON )は次のとおりです。
次のコードスニペットのいずれかを使用して、JSON文字列表現をJSONに変換できます。
ParseJSONValueを使用:
procedure ConsumeJsonString;
var
LJSONObject: TJSONObject;
begin
LJSONObject := nil;
try
{ convert String to JSON }
LJSONObject := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(GJSONString), 0) as TJSONObject;
{ output the JSON to console as String }
Writeln(LJSONObject.ToString);
finally
LJSONObject.Free;
end;
そのアプローチは、as行でクラスの無効な型キャストで失敗します!!
Parseを使用:
procedure ConsumeJsonBytes;
var
LJSONObject: TJSONObject;
begin
LJSONObject := nil;
try
LJSONObject := TJsonObject.Create;
{ convert String to JSON }
LJSONObject.Parse(BytesOf(GJSONString), 0);
{ output the JSON to console as String }
Writeln(LJSONObject.ToString);
finally
LJSONObject.Free;
end;
end;
Embarcaderoの例では、入力JSONはコード内で文字列として宣言されています。
const
GJSONString =
'{' +
' "name": {'+
' "A JSON Object": {' +
' "id": "1"' +
' },' +
' "Another JSON Object": {' +
' "id": "2"' +
' }' +
' },' +
' "totalobjects": "2"' +
'}';
私が処理しているJSONはBetFairからのものです。有効です( http://jsonformatter.curiousconcept.com/ および http://www.freeformatter.com/json-validatorで検証されます)。 html および http://jsonlint.com/ ):
[{
"caption": "Get the number of soccer markets",
"methodName": "SportsAPING/v1.0/listEventTypes",
"params": {
"filter": {
"eventTypeIds": [
1
]
}
}
},
{
"caption": "Get the next horse race in the UK",
"methodName": "SportsAPING/v1.0/listMarketCatalogue",
"params": {
"filter": {
"eventTypeIds": [
7
],
"marketCountries": [
"GB"
],
"marketTypeCodes": [
"WIN"
],
"marketStartTime": {
"from": "2013-04-11T11:03:36Z"
}
},
"sort": "FIRST_TO_START",
"maxResults": "1",
"marketProjection": [
"COMPETITION",
"EVENT",
"EVENT_TYPE",
"MARKET_DESCRIPTION",
"RUNNER_DESCRIPTION"
]
}
},
{
"caption": "Get the 2 best prices, rolled up to £10 for the London Mayor Election 2016",
"methodName": "SportsAPING/v1.0/listMarketBook",
"params": {
"marketIds": [
"1.107728324"
],
"priceProjection": {
"priceData": [
"EX_BEST_OFFERS"
],
"exBestOffersOverrides": {
"bestPricesDepth": "2",
"rollupModel": "STAKE",
"rollupLimit": "10"
}
}
}
},
{
"caption": "Get my current unmatched bets",
"methodName": "SportsAPING/v1.0/listCurrentOrders",
"params": {
"orderProjection": "EXECUTABLE"
}
},
{
"caption": "Get my application keys",
"methodName": "AccountAPING/v1.0/getDeveloperAppKeys",
"params": {
}
}]
私はこれを文字列として宣言していませんが、ファイルからそれを読んでいます:
TFile.ReadAllText(aFileName);
ファイルの読み取りは正常に完了しました。
これが問題の原因となるコードです。上記の行のように、Embarcaderoのドキュメントから推奨されているアプローチ2を使用しました。それは失敗しました。デバッグのために、アプローチをより多くの変数に分割しました。
Embarcaderoのドキュメントによると、何らかの理由で解析が失敗した場合、vParseResultは負の値になります。ありません。ただし、解析に成功しても(試行の2行目)vJSONPairはnilになり、例外が発生します。
procedure TfMain.loadScenarioData(aFilename: string);
var
vJSONString: string;
vJSONScenario: TJSONObject;
vJSONPair: TJSONPair;
vJSONScenarioEntry: TJSONValue;
vJSONScenarioValue: string;
I: Int16;
vParseResult: Integer;
begin
vJSONString := TFile.ReadAllText(aFileName);
vJSONScenario := nil;
try
vJSONScenario := TJSONObject.Create;
vParseResult := vJSONScenario.Parse(BytesOf(vJSONString),0);
if vParseResult >= 0 then
begin
//BetFair Specific 'caption' key
vJSONPair := vJSONScenario.Get('caption');
vJSONScenarioEntry := vJSONPair.JsonValue;
vJSONScenarioValue := vJSONScenarioEntry.Value;
cbScenario.Items.Add(vJSONScenarioValue);
end;
finally
vJSONScenario.Free;
end;
end;
IDEおよび言語に関する適切なドキュメントがない場合、またはドキュメントが完全または適切でない場合、この種のことはひどい時間の無駄であり、作業を完了する際に問題を引き起こします。言語やライブラリを使用して問題を解決し、それらに関する問題を解決するのではなく、不十分で、曖昧で、見つけにくいドキュメントを作成すること。
TJSONObject.ParseJSONValue()
は、解析が失敗した場合、nil
ポインターを返します。 Embarcaderoの例では、その状態はチェックされません。解析が失敗した場合、as
演算子によって発生する「無効な型キャスト」エラーの原因になります。
TJSONObject.Parse()
は、解析に失敗した場合、-1を返します。 Embarcaderoの例では、その状態はチェックされません。
TJSONObject
は文字ではなくバイトを解析するため、TFile.ReadAllText()
を使用しないことをお勧めします。これは、バイトが読み込まれ、TEncoding.Default
_を使用してUTF-16にデコードします部品表。特定の例では、JSONにはASCII文字のみが含まれているため、これは問題ではありません。ただし、非ASCII Unicode文字を使用する場合は問題になる可能性があります。これが、TJSONObject.ParseJSONValue()
の_IsUTF8
_パラメーターがデフォルトでtrueになっている理由です)。
いずれの場合でも、コードは表示したJSONデータの構造と一致しません。 JSONデータはオブジェクトの配列であるため、解析される最初のアイテムはTJSONArray
ではなくTJSONObject
になります。 TSJONObject.ParseJSONValue()
を使用すると、TJSONValue
に型キャストできるTJSONArray
を返します。
_procedure TfMain.loadScenarioData(aFilename: string);
var
vJSONBytes: TBytes;
vJSONScenario: TJSONValue;
vJSONArray: TJSONArray;
vJSONValue: TJSONValue;
vJSONObject: TJSONObject;
vJSONPair: TJSONPair;
vJSONScenarioEntry: TJSONValue;
vJSONScenarioValue: TJSONString;
begin
vJSONBytes := TFile.ReadAllBytes(aFileName);
vJSONScenario := TJSONObject.ParseJSONValue(vJSONBytes, 0);
if vJSONScenario <> nil then
try
//BetFair Specific 'caption' key
vJSONArray := vJSONScenario as TJSONArray;
for vJSONValue in vJSONArray do
begin
vJSONObject := vJSONValue as TJSONObject;
vJSONPair := vJSONObject.Get('caption');
vJSONScenarioEntry := vJSONPair.JsonValue;
vJSONScenarioValue := vJSONScenarioEntry as TJSONString;
cbScenario.Items.Add(vJSONScenarioValue.Value);
end;
finally
vJSONScenario.Free;
end;
end;
_
または単に:
_procedure TfMain.loadScenarioData(aFilename: string);
var
vJSONScenario: TJSONValue;
vJSONValue: TJSONValue;
begin
vJSONScenario := TJSONObject.ParseJSONValue(TFile.ReadAllBytes(aFileName), 0);
if vJSONScenario <> nil then
try
//BetFair Specific 'caption' key
for vJSONValue in vJSONScenario as TJSONArray do
begin
cbScenario.Items.Add(((vJSONValue as TJSONObject).Get('caption').JsonValue as TJSONString).Value);
end;
finally
vJSONScenario.Free;
end;
end;
_
代わりにTJSONObject.Parse()
を使用する場合、TJSONArray
はParse()
を呼び出しているオブジェクトの子として追加されますが、名前のない配列なので、取得する必要がありますインデックスによる配列:
_procedure TfMain.loadScenarioData(aFilename: string);
var
vJSONBytes: TBytes;
vJSONScenario: TJSONObject;
vJSONArray: TJSONArray;
vJSONValue: TJSONValue;
vJSONObject: TJSONObject;
vJSONPair: TJSONPair;
vJSONScenarioEntry: TJSONString;
vJSONScenarioValue: string;
vParseResult: Integer;
begin
vJSONBytes := TFile.ReadAllBytes(aFileName);
vJSONScenario := TJSONObject.Create;
try
vParseResult := vJSONScenario.Parse(vJSONBytes, 0);
if vParseResult >= 0 then
begin
//BetFair Specific 'caption' key
vJSONArray := vJSONScenario.Get(0) as TJSONArray;
for vJSONValue in vJSONArray do
begin
vJSONObject := vJSONValue as TJSONObject;
vJSONPair := vJSONObject.Get('caption');
vJSONScenarioEntry := vJSONPair.JsonString;
vJSONScenarioValue := vJSONScenarioEntry.Value;
cbScenario.Items.Add(vJSONScenarioValue);
end;
end;
finally
vJSONScenario.Free;
end;
end;
_
または単に:
_procedure TfMain.loadScenarioData(aFilename: string);
var
vJSONScenario: TJSONObject;
vJSONValue: TJSONValue;
vParseResult: Integer;
begin
vJSONScenario := TJSONObject.Create;
try
vParseResult := vJSONScenario.Parse(TFile.ReadAllBytes(aFileName), 0);
if vParseResult >= 0 then
begin
//BetFair Specific 'caption' key
for vJSONValue in vJSONScenario.Get(0) as TJSONArray do
begin
cbScenario.Items.Add(((vJSONValue as TJSONObject).Get('caption').JsonValue as TJSONString).Value);
end;
end;
finally
vJSONScenario.Free;
end;
end;
_
Update:代わりに SuperObject を試してみると、コードは少し単純になります。例:
_procedure TfMain.loadScenarioData(aFilename: string);
var
vJSONScenario: ISuperObject;
vJSONArray: ISuperObject;
vJSONObject: ISuperObject;
vJSONScenarioValue: string;
I: Integer;
begin
vJSONScenario := TSuperObject.ParseFile(aFileName);
//BetFair Specific 'caption' key
vJSONArray := vJSONScenario.AsArray;
for I := 0 to vJSONArray.Length-1 do
begin
vJSONObject := vJSONArray[I].AsObject;
vJSONScenarioValue := vJSONObject.S['caption'];
cbScenario.Items.Add(vJSONScenarioValue);
end;
end;
_
Remyのコードは、次の調整後に正しいです。
var
vJSONBytes: TBytes;
vJSONScenario: TJSONValue;
vJSONArray: TJSONArray;
vJSONValue: TJSONValue;
vJSONObject: TJSONObject;
vJSONPair: TJSONPair;
vJSONScenarioEntry: TJSONString;
vJSONScenarioValue: TJSONValue;
begin
vJSONBytes := TFile.ReadAllBytes(aFileName);
vJSONScenario := TJSONObject.ParseJSONValue(vJSONBytes, 0);
if vJSONScenario <> nil then
try
//BetFair Specific 'caption' key
vJSONArray := vJSONScenario as TJSONArray;
for vJSONValue in vJSONArray do
begin
vJSONObject := vJSONValue as TJSONObject;
vJSONPair := vJSONObject.Get(pScenarioKey);
vJSONScenarioEntry := vJSONPair.JsonString;
//vJSONScenarioValue := vJSONScenarioEntry.Value;
vJSONScenarioValue := vJSONPair.JsonValue;
cbScenario.Items.Add(vJSONScenarioValue.ToString);
end;
finally
vJSONScenario.Free;
end;
end;