用Delphi解析可空的TJSONObject

Pep*_*Pep 3 delphi json

我正在使用Delphi XE3.我有一个JSON流,其中一个对象可以为null.也就是说,我可以收到:

"user":null
Run Code Online (Sandbox Code Playgroud)

要么

"user":{"userName":"Pep","email":"pep@stackoverflow.com"}
Run Code Online (Sandbox Code Playgroud)

我想区分这两种情况,我尝试使用这段代码:

var 
  jUserObject: TJSONObject;

jUserObject := TJSONObject(Get('user').JsonValue);
if (jUserObject.Null) 
then begin
  FUser := nil;
end else begin
  FUser := TUser.Create;
  with FUser, jUserObject do begin
    FEmail := TJSONString(Get('email').JsonValue).Value;
    FUserName := TJSONString(Get('userName').JsonValue).Value;
  end;
end;
Run Code Online (Sandbox Code Playgroud)

如果我把一个断点排成一行if (jUserObject.Null) then begin并且我将鼠标放在jUserObject.Null它上面说jUserObject.Null = True是否"user":null,它说jUserObject.Null = False是否"user":{"userName":"Pep","email":"pep@stackoverflow.com"}

但是,如果我使用调试器进入该行,jUserObject.Null将调用以下XE3库代码:

function TJSONAncestor.IsNull: Boolean;
begin
  Result := False;
end;
Run Code Online (Sandbox Code Playgroud)

所以,我总是得到Falseif就算一句,"user":null.

我想我总是有一个解决方法,即捕获在执行"user":nullGet('email').JsonValue执行时引发的异常,以便区分值是否为null,但这看起来并不那么优雅.

如何判断JSON对象在JSON流中是否具有空值?

Rem*_*eau 5

Get()返回一个TJSONPair.如果有"user":null,TJSONPair.JsonValue属性将返回一个TJSONNull对象,而不是一个TJSONObject对象.你的代码没有考虑到这种可能性.它假设JsonValue始终是a TJSONObject并且不验证类型转换.

有两种方法可以解决这个问题.

  1. TJSONPair有自己的Null属性,指定它JsonValue是否为空值:

    var
      JUser: TJSONPair;
      jUserObject: TJSONObject;
    
    jUser := Get('user');
    if jUser.Null then begin
      FUser := nil;
    end else begin
      // use the 'as' operator for type validation in
      // case the value is something other than an object...
      jUserObject := jUser.JsonValue as TJSONObject;
      ...
    end;
    
    Run Code Online (Sandbox Code Playgroud)
  2. 使用is运算符在测试JsonValue之前测试类的类型:

    var
      JUser: TJSONPair;
      jUserObject: TJSONObject;
    
    jUser := Get('user');
    if jUser.JsonValue is TJSONNull then begin
      FUser := nil;
    end
    else if jUser.JsonValue is TJSONObject then begin
      jUserObject := TJSONObject(jUser.JsonValue);
      ...
    end else begin
      // the value is something other than an object...
    end;
    
    Run Code Online (Sandbox Code Playgroud)