使用 TJSONDataObject 读取嵌套对象中 JSON 字符串值的正确语法

Correct syntax to read the value of a JSON string inside nested object using TJSONDataObject

有人可以用正确的语法帮助我访问嵌套对象中的字符串,使用 JSON来自 Andreas Hausladen

的 DataObjects

我有一个从 API 返回的 JSON 字符串,其中包含一个客户数组,后跟一个游标分页对象(元),例如

  {
  "customers": [
    {
      "id": "CU000DWEQWMRN4",
      "email": "theemail@outlook.com",
      "metadata": {
                         "member_name": "BLOGGS jim",
                         "membership_id": "4088"
                       }
    },
    {
      "id": "CU000DVEKR579S",
      "email": "anotheremail@outlook.com",
      "metadata": {
                        "membership_id": "5647"
                         }
    }
  ],
  "meta": {
              "cursors": {
                             "before": null,
                             "after": "ID456"
                             },
                  "limit": 50
               }
}

我试图在最后 meta 对象中获取 beforeafter 的值

我试过的

var  Obj: TJsonObject;
       AfterID : string;
  
  begin
  Obj := TJsonObject.Parse(theJSON) as TJsonObject;
  AfterID :=    Obj['meta']['cursors']['after']  ; 

问题 我收到错误消息 cannot convert object to string

我也试过了

  var  
     Obj: TJsonObject;
     AfterID : string;
   begin   
   obj :=  Obj['meta'];
   Obj := Obj['cursors'];
   AfterID := Obj['after'];

问题 我收到错误消息 cannot convert object to string

我也尝试过许多其他语法组合,但我不会用所有这些来混淆问题!

我很困惑,因为我的语法是正确的,当我用一个稍微不同的 JSON 从另一个 API 返回时,我的语法是正确的,它具有更简单的游标分页结构,例如

{
  "items": [
    {
      "event": "accepted",
      "id": "G3wOhh",
      "user-variables": {},
      "log-level": "info",
      "method": "smtp"
    },
    {
      "event": "accepted",
      "id": "KLT56",
      "user-variables": {},
      "log-level": "info",
      "method": "smtp"
    }
  ],
  "paging": {
    "previous": "line 4",
    "first": "line 1",
    "last": "line 12",
    "next": "line 6"
  }
}

用这个JSON,用

var
      Obj : TJsonObject;
      nextID : string;
begin
 Obj := TJsonObject.Parse(TheReturnedJSON) as TJDOJsonObject; 
 nextID := Obj['paging']['next'];

我得到了正确的返回值

TJsonObject的默认[]属性是它的Values[]属性,其中returns一个TJsonDataValueHelper:

property Values[const Name: string]: TJsonDataValueHelper read GetValue write SetValue; default;

所以,阅读 Obj['cursors'] returns TJsonDataValueHelper,而不是 TJsonObject

TJsonDataValueHelper的默认[]属性是它的O[]属性,其中returns一个TJsonDataValueHelper代表一个JSON 对象,不是 JSON 字符串:

property O[const Name: string]: TJsonDataValueHelper read {$IFDEF BCB}GetObj{$ELSE}GetObject{$ENDIF} write SetObject; default;

TJsonDataValueHelper 有一个 S[] 属性 来读取字符串值:

property S[const Name: string]: string read GetObjectString write SetObjectString;        // returns '' if property doesn't exist, auto type-cast except for array/object

所以,试试这个:

AfterID := Obj['meta']['cursors'].S['after']; 
nextID := Obj['paging'].S['next']; 

或者,根本不使用 TJsonDataValueHelperTJsonObject 有一个 O[] 属性,returns 一个 TJsonObject,还有一个 S[] 属性 用于读取字符串:

property S[const Name: string]: string read GetString write SetString;        // returns '' if property doesn't exist, auto type-cast except for array/object
...
property O[const Name: string]: TJsonObject read {$IFDEF BCB}GetObj{$ELSE}GetObject{$ENDIF} write SetObject;   // auto creates object on first access

例如:

AfterID := Obj.O['meta'].O['cursors'].S['after']; 
nextID := Obj.O['paging'].S['next']; 

顺便说一句,我会在 Remy 的回答中补充说,由于我的示例 JSON 中 'before' 的值为 null,我发现我必须使用以下代码避免在将该值读取为 Obj.Values['meta'].O['cursors'].S['before'];

时出现另一个类型转换错误
var
  temp : variant;
  BeforeID : string;
begin
  //read the value into a variant by using .V just in case it's null. 
  //if it is then reading a string using .S gives an error
  temp := Obj.Values['meta'].O['cursors'].V['before']; 
  if not VarIsNull(temp) then  // it's not a null so we can convert to a string
    BeforeID := VarToStr(temp)
  else                         // it is null so assign whatever string is appropriate  
    BeforeID := '';  

但使用 .V 只是一个猜测。我很想知道所有这些都记录在哪里!