使用Embarcadero代码示例使用TJSONObject解析有效JSON失败,出现异常

使用Embarcadero代码示例使用TJSONObject解析有效JSON失败,出现异常,json,delphi,parsing,Json,Delphi,Parsing,以下是Embarcadero帮助()中的示例代码: 您可以使用以下代码片段之一将JSON字符串表示转换为JSON 使用ParseJSONValue: 过程ConsumeJsonString; 变量 LJSONObject:TJSONObject; 开始 LJSONObject:=nil; 尝试 {将字符串转换为JSON} LJSONObject:=TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(GJSONString),0)作为TJSONO

以下是Embarcadero帮助()中的示例代码:

您可以使用以下代码片段之一将JSON字符串表示转换为JSON

使用ParseJSONValue

过程ConsumeJsonString;
变量
LJSONObject:TJSONObject;
开始
LJSONObject:=nil;
尝试
{将字符串转换为JSON}
LJSONObject:=TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(GJSONString),0)作为TJSONObject;
{将JSON作为字符串输出到控制台}
Writeln(LJSONObject.ToString);
最后
LJSONObject.Free;
结束;
这种方法失败了,因为as行上的类类型转换无效

使用解析

过程消耗jsonbytes;
变量
LJSONObject:TJSONObject;
开始
LJSONObject:=nil;
尝试
LJSONObject:=TJsonObject.Create;
{将字符串转换为JSON}
解析(BytesOf(GJSONString),0);
{将JSON作为字符串输出到控制台}
Writeln(LJSONObject.ToString);
最后
LJSONObject.Free;
结束;
结束;
在Embarcadero示例中,输入JSON在代码中声明为字符串:

const
GJSONString=
'{' +
““名称”:{”+
““一个JSON对象”:{”+
““id”:“1”+
'        },' +
““另一个JSON对象”:{”+
“id”:“2”+
'        }' +
'    },' +
““totalobjects”:“2”+
'}';
我正在处理的JSON来自BetFair。有效(通过和验证):

[{
“说明”:“获取足球市场的数量”,
“方法名称”:“SportsAPING/v1.0/listEventTypes”,
“参数”:{
“过滤器”:{
“EventTypeId”:[
1.
]
}
}
},
{
“说明”:“在英国参加下一场赛马”,
“方法名称”:“SportsAPING/v1.0/ListMarketCatalog”,
“参数”:{
“过滤器”:{
“EventTypeId”:[
7.
],
“市场国家”:[
“GB”
],
“市场类型代码”:[
“赢”
],
“市场启动时间”:{
“发件人”:“2013-04-11T11:03:36Z”
}
},
“排序”:“第一次开始”,
“maxResults”:“1”,
“市场预测”:[
“竞争”,
“活动”,
“事件类型”,
“市场描述”,
“跑步者描述”
]
}
},
{
“说明”:“为2016年伦敦市长选举获得2个最优惠价格,总计10英镑”,
“方法名称”:“SportsAPING/v1.0/listMarketBook”,
“参数”:{
“市场化”:[
"1.107728324"
],
“价格预测”:{
“价格数据”:[
“EX_BEST_优惠”
],
“exBestOffersOverrides”:{
“最佳价格深度”:“2”,
“汇总模型”:“桩”,
“rollupLimit”:“10”
}
}
}
},
{
“说明”:“获取我当前未匹配的赌注”,
“方法名称”:“SportsAPING/v1.0/listCurrentOrders”,
“参数”:{
“orderProjection”:“可执行文件”
}
},
{
“标题”:“获取我的应用程序密钥”,
“方法名”:“AccountAPING/v1.0/getDeveloperAppKeys”,
“参数”:{
}
}]
我不是将其声明为字符串,而是从文件中读取它,因此:

TFile.ReadAllText(aFileName);
文件读取成功

下面是导致问题的代码。我已经使用了Embarcadero文档中推荐的方法2,如上所述。那失败了。为了调试的目的,我将该方法拆分为多个变量

根据Embarcadero文件,vParseResult将为负值 如果解析因任何原因失败,则返回值。事实并非如此。但是,即使解析成功(try之后的第二行),vJSONPair最终还是为nil,这会导致异常:

过程TfMain.loadScenarioData(文件名:字符串);
变量
vJSONString:string;
vJSONScenario:TJSONObject;
vJSONPair:TJSONPair;
vJSONScenarioEntry:TJSONValue;
vJSONScenarioValue:字符串;
I:Int16;
vParseResult:整数;
开始
vJSONString:=TFile.ReadAllText(aFileName);
vJSONScenario:=零;
尝试
vJSONScenario:=TJSONObject.Create;
vParseResult:=vJSONScenario.Parse(BytesOf(vJSONString),0);
如果vParseResult>=0,则
开始
//BetFair特定的“标题”键
vJSONPair:=vJSONScenario.Get('caption');
vJSONScenarioEntry:=vJSONPair.JsonValue;
vJSONScenarioValue:=vJSONScenarioEntry.Value;
cbScenario.Items.Add(vJSONScenarioValue);
结束;
最后
免费;
结束;
结束;

这种没有足够的IDE和语言文档,或者文档不完整或不充分的情况是一种严重的时间浪费,给我带来了完成工作的问题。我需要使用语言和库来解决问题,而不是使用它们来解决问题,或者使用不充分、不明确和难以找到的文档来解决问题。

TJSONObject.ParseJSONValue()
如果解析失败,将返回一个
nil
指针。Embarcadero的例子没有检查这种情况。如果解析失败,这将解释
as
运算符引发的“无效类型转换”错误

TJSONObject.Parse()
如果解析失败,则返回-1。Embarcadero的例子没有检查这种情况

因为
TJSONObject
解析字节,而不是字符,所以我建议您不要使用
TFile.ReadAllText()
,它将读取字节并使用
TEncoding.Default
将其解码为UTF-16(如果文件没有BOM)。在你的
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;
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;
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;
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;