GOLANG 解组动态 JSON

Posted

技术标签:

【中文标题】GOLANG 解组动态 JSON【英文标题】:GOLANG unmarshal dynamic JSON 【发布时间】:2022-01-21 01:55:22 【问题描述】:

我是 GOLANG 的新手。

我已经尝试了很长一段时间来解组具有动态结构的以太坊 RPC JSON。我没有工作过 GOLANG 结构和映射设置,我能够获得 stateDiff 条目(3),但所有较低的结构似乎都没有填充任何数据。所以我能够遍历所有 3 个条目,但不知道如何访问下面的值,并且在转储解组结果时,我看到 GOLANG 并没有将数据传递到 StateDiff

JSON 文件:


   "jsonrpc":"2.0",
   "id":1,
   "result":
      "output":"0x0000000000000000000000000000000000000000000000000000000000000001",
      "stateDiff":
         "0x0000000000000000000000000000000000000000":
            "balance":
               "*":
                  "from":"0x45acecdfadb71366cf",
                  "to":"0x45aced3909536ccacf"
               
            ,
            "code":"=",
            "nonce":"=",
            "storage":
               
            
         ,
         "0x07865c6e87b9f70255377e024ace6630c1eaa37f":
            "balance":"=",
            "code":"=",
            "nonce":"=",
            "storage":
               "0x86a60af761556602732bbdeaef13ba6e2481f83362d3489389f51353d86a6ac3":
                  "*":
                     "from":"0x0000000000000000000000000000000000000000000000000000000000000000",
                     "to":"0x0000000000000000000000000000000000000000000000000000000000002710"
                  
               ,
               "0xb0cf6f3c0836765b9dee3d1537458f10fe99447508adc172c1f633ac7352aaa8":
                  "*":
                     "from":"0x00000000000000000000000000000000000000000000000000092f379a04d2b0",
                     "to":"0x00000000000000000000000000000000000000000000000000092f379a04aba0"
                  
               
            
         ,
         "0x6dbe810e3314546009bd6e1b29f9031211cda5d2":
            "balance":
               "*":
                  "from":"0x41c41fc2c0247860",
                  "to":"0x41c3c66723c4155c"
               
            ,
            "code":"=",
            "nonce":
               "*":
                  "from":"0x741",
                  "to":"0x742"
               
            ,
            "storage":
               
            
         
      ,
      "trace":[
         
      ],
      "vmTrace":null
   

我试图将 JSON 解组为以下结构(在许多结构中),但我无法从 result>stateDiff>0x00000000000000000000000000000000000000000>balance>*>from 获取值 下面的结构只是我尝试过的众多之一。我在 0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 任何任何东西下面的任何东西


type structChange struct 
    Changes map[string]string `json:"*"`


type structStateDiff struct 
    Balance *structChange            `json:"balance"`
    Code    string                    `json:"code"`
    Nonce   string                    `json:"nonce"`
    Storage map[string]*structChange `json:"storage"`


type res_trace_replayTransaction struct 
    Jsonrpc string `json:"jsonrpc"`
    ID      int    `json:"id"`
    Result  struct 
        Output    string                      `json:"output"`
        StateDiff map[string]*structStateDiff `json:"stateDiff"`
        Trace     []interface               `json:"trace"`
        VMTrace   interface                 `json:"vmTrace"`
     `json:"result"`

编辑: 元帅代码

retObj := rpcCall(jstring)

var callResponse res_trace_replayTransaction
err := json.Unmarshal(retObj, &callResponse)

【问题讨论】:

请阅读 Go 教程:go.dev/doc/tutorial/getting-started,然后阅读 Go Json 教程,例如 gobyexample.com/json,我强烈建议不要匿名。而是为每个结构定义*** types,然后在包含它的结构中使用类型名称。 已阅读,但我无法解决此问题。 然后再仔细阅读一下 json 示例。前 3 段中的一段告诉您您做错了什么:“只有导出的字段才会在 JSON 中编码/解码。字段必须以大写字母开头才能导出。” "我没有工作过的 GOLANG 结构和地图设置" 我会为此使用 structs - 不是匿名的,而是命名的结构类型 - 但你不需要需要使用structs。您也可以执行go.dev/play/p/P4ryK-9wuVl 之类的操作 - 缺点是您必须自己进行所有类型检查,这就是 structs 更好的原因 另外你没有包含你的解组代码 【参考方案1】:

请注意,默认情况下,encoding/json 包可以将 JSON 字符串解组为 Go string,它可以将 JSON 对象解组为 Go map 或 Go struct。此外,它可以将任何 JSON 值解组为空的 interface

另请注意,Go 是一种静态类型的语言,如果您指定一个值为T1 类型,那么在运行时,您无法将其类型更改为T2。没有办法做到这一点,没有办法改变一个值的类型。

因此,如果您将某个字段定义为某种 struct 类型,则默认情况下,您无法将 JSON 字符串解组到其中。同样,如果您将字段定义为 string 类型,默认情况下,您无法将 JSON 对象解组到其中。

但由于 JSON 本身允许动态结构,encoding/json 包提供了两个接口,使您能够自定义 JSON 的格式为 marshaled 和 unmarshaled。

因此,如果您有一个 JSON 属性(例如 "balance""nonce"),可以是 "="(字符串)或 ... (对象),您需要声明一个自定义类型实现了知道如何正确编组和解组 JSON 值的 json.Marshalerjson.Unmarshaler 接口。

例如:

type structChange struct 
    Changes map[string]string `json:"*"`


func (s structChange) MarshalJSON() ([]byte, error) 
    // if empty retrun `"="`
    if len(s.Changes) == 0 
        return []byte(`"="`), nil
    

    // otherwise marshal as is
    type T structChange
    return json.Marshal(T(s))


func (s *structChange) UnmarshalJSON(data []byte) error 
    // if `"="`, ignore
    if string(data) == `"="` 
        return nil
    

    // otherwise assume it's a valid object
    type T structChange
    return json.Unmarshal(data, (*T)(s))

注意:上面的临时类型T用于避免无限递归调用MarshalJSONUnmarshalJSON方法引起的堆栈溢出。

https://go.dev/play/p/yfsTrMozZ2Z

【讨论】:

所以问题在于平衡的“”字段。我现在已经删除了它并且它可以工作,不幸的是这不是解决方案。如何解组“”键域? @ThomasMiller 我不明白你在说什么。请使用新代码更新您的问题,并清楚地解释您现在面临的问题/错误。 @ThomasMiller 通常你需要做一个零检查,例如if x != nil ...,表示您想要使用的任何x,但在使用它的上下文中可能nil。如果没有看到实际代码和恐慌的完整堆栈跟踪,就不可能更具体。如果您需要更多帮助,您需要使用新信息更新问题。或者打开一个新问题。 非常感谢。我现在实际上找到了这个解决方案并看到了您的回复。我在结构中检查了太高的 nil 而不是实际重要的最低字段。现在,我抓住了 nil 的情况,它不会抛出错误

以上是关于GOLANG 解组动态 JSON的主要内容,如果未能解决你的问题,请参考以下文章

在 Golang 中解组 XML 时如何在 interface 中获取数据?

在 Golang 中将字符串解组为类似结构的结构

当 JSON 字段键是日期时,如何将 JSON 对象解组为 Golang 结构?

Golang如何解组嵌套的JSON数据的子集

golang学习随便记5

嵌入式结构的多态 JSON 解组