【问题标题】:Correct syntax to read the value of a JSON string inside nested object using TJSONDataObject使用 TJSONDataObject 读取嵌套对象内 JSON 字符串值的正确语法
【发布时间】:2023-03-21 11:45:01
【问题描述】:

有人可以帮助我使用 Andreas Hausladen 的 JSONDataObjects 访问嵌套对象内的字符串的正确语法

我有一个从 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']  ; 

问题 我收到错误消息无法将对象转换为字符串

我也试过了

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

问题 我收到错误消息无法将对象转换为字符串

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

我很困惑,因为当我使用从另一个具有更简单光标分页结构的 API 重新调整的稍微不同的 JSON 做同样的事情时,我的语法是正确的,例如

{
  "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'];

我得到了正确的返回值

【问题讨论】:

    标签: json delphi-2009


    【解决方案1】:

    TJsonObject 的默认[] 属性是它的Values[] 属性,它返回一个TJsonDataValueHelper

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

    因此,读取Obj['cursors'] 会返回TJsonDataValueHelper,而不是TJsonObject

    TJsonDataValueHelper 的默认[] 属性是它的O[] 属性,它返回代表JSON 对象的TJsonDataValueHelper,而不是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 有一个返回 TJsonObjectO[] 属性和一个用于读取字符串的 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']; 
    

    【讨论】:

    • 好的,谢谢。我已将其标记为正确,但我能问一下您是在哪里找到的吗?我可以在这里找到的唯一“文档”github.com/ahausladen/JsonDataObjects 非常简短,没有提及 .O 或 .S 并且只有一个非常简单的示例。有没有更好的文档?
    • @user2834566 我通过查看 JSONDataObject 的源代码本身就得到了这些信息。
    • 啊,好吧,这也是我一直在尝试做的事情,但有点遗憾的是,这样一个有用的类没有在某处记录至少一句话说什么属性和方法做什么,甚至是对源中的每一个的快速评论。我花了两三天的假,试图弄清楚如何使用这门课,然后终于在这里发帖,害怕被某些其他 SO 用户击落。不包括你雷米,我非常感谢你的帮助
    【解决方案2】:

    顺便说一句,我会在 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 只是一个猜测。我很想知道所有这些都记录在哪里!

    【讨论】:

    • 仅供参考,VarToStr() 处理空值以返回空白字符串,因此您不需要 VarIsNull() 检查。但我会尽可能避免使用VariantTJsonDataValueHelper 有一个 Typ 属性来告诉你一个值是字符串还是空值还是 ... 等等,还有一个 IsNull 方法。虽然我不确定为非对象/数组获取TJsonDataValueHelper 的最佳方法。
    • 我可能只是说根本不使用TJsonDataValueHelper,而是按原样使用TJsonObject,它也有IsNull,例如:var cursors: TJsonObject; BeforeID : string; begin cursors := Obj.O['meta'].O['cursors']; if not cursors.IsNull('before') then BeforeID := cursors.S['before'];或者,我认为TJsonObject.S[]为您处理nullBeforeID := Obj.O['meta'].O['cursors'].S['before'];
    • 你是对的,如果没有适当的文档,这有点令人困惑!
    • 太棒了,谢谢雷米。所有这些信息对于使用此类编写一些合理且易读的代码大有帮助。 (必须承认,相当丢脸的是,我为登山协会编写的一个相当大的远程数据库前端的文档已经过时了一两年!有一天我会抽空做文档而不是开发,但虽然它仍然只是我在做编程,但创造比记录更有趣)。
    • 仅供阅读本文的任何人使用。雷米,你是对的,cursors := Obj.O['meta'].O['cursors']; if not cursors.IsNull('before') then... 确实可以正常工作,但 Obj.O['meta'].O['cursors'].S['before']` 似乎无法处理空值。我希望它会返回一个空字符串,但它只会给出一个转换错误。没关系,`if not cursors.IsNull()` 构造非常方便。
    猜你喜欢
    • 2021-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多