GOLANG解析动态JSON

huangapple go评论79阅读模式
英文:

GOLANG unmarshal dynamic JSON

问题

我对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>0x0000000000000000000000000000000000000000>balance>*>from之类的值。下面的结构只是我尝试过的众多结构之一。我无法获取到0x0000000000000000000000000000000000000000条目下面的任何内容。

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)
英文:

I am very new to GOLANG.

I have been trying for quite some time now to unmarshal an ethereum RPC JSON which has a dynamic structure. No GOLANG struct and map setup I did worked and I am able to get the stateDiff entries (3) but all lower structs seem not to be filled ith any data. So I am able to loop through all the 3 entries but then don't know how to access the values below and when dumping the unmarshal result, I see that GOLANG is not delivering the data anyway into StateDiff

JSON FILE:

{
   "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
   }
}

I have tried to unmarshal the JSON into the following structure (among many) and i can't get the values such as result>stateDiff>0x0000000000000000000000000000000000000000>balance>*>from
Struct below is just one of many i tried. I can't get anything below the entry 0x0000000000000000000000000000000000000000


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"`
}

EDIT:
Code for umarshal

retObj := rpcCall(jstring)

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

答案1

得分: 2

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

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

因此,如果你将一个字段定义为某个 struct 类型,你不能默认情况下将 JSON 字符串解组为它。同样,如果你将一个字段定义为 string 类型,你不能默认情况下将 JSON 对象解组为它。

但是,由于 JSON 本身允许动态结构,encoding/json 包提供了两个接口,使你能够自定义 JSON 的编组解组方式。

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

例如:

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

func (s structChange) MarshalJSON() ([]byte, error) {
	// 如果为空,则返回 `"="`
	if len(s.Changes) == 0 {
		return []byte(`"="`), nil
	}

	// 否则按原样编组
	type T structChange
	return json.Marshal(T(s))
}

func (s *structChange) UnmarshalJSON(data []byte) error {
	// 如果是 `"="`,则忽略
	if string(data) == `"="` {
		return nil
	}

	// 否则假设它是一个有效的对象
	type T structChange
	return json.Unmarshal(data, (*T)(s))
}

<sub>注意:上面的临时类型 T 用于避免由于对 MarshalJSONUnmarshalJSON 方法的无限递归调用而导致的堆栈溢出。</sub>

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

英文:

Note that by default the encoding/json package can unmarshal a JSON string into a Go string, and it can unmarshal a JSON object into a Go map or a Go struct. Additionally it can unmarshal any JSON value into an empty interface{}.

Also note that Go is a statically typed language, if you specify a value to be of type T1 then, at runtime, you cannot change it's type to T2. There is just no way to do it, no way to change a value's type.

So if you define a field to be of some struct type, you cannot, by default, unmarshal a JSON string into it. And equally if you define a field to be of type string, you cannot, by default, unmarshal a JSON object into it.

But because JSON itself allows for a dynamic structure the encoding/json package provides two interfaces that give you the ability to customize how the JSON is marshaled and unmarshaled.

So if you have a JSON property (e.g. &quot;balance&quot; or &quot;nonce&quot;) that can be either &quot;=&quot; (a string), or { ... } (an object), you will need to declare a custom type that implements the json.Marshaler and json.Unmarshaler interfaces that know how to properly marshal and unmarshal the JSON value.

For example:

type structChange struct {
	Changes map[string]string `json:&quot;*&quot;`
}

func (s structChange) MarshalJSON() ([]byte, error) {
	// if empty retrun `&quot;=&quot;`
	if len(s.Changes) == 0 {
		return []byte(`&quot;=&quot;`), nil
	}

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

func (s *structChange) UnmarshalJSON(data []byte) error {
	// if `&quot;=&quot;`, ignore
	if string(data) == `&quot;=&quot;` {
		return nil
	}

	// otherwise assume it&#39;s a valid object
	type T structChange
	return json.Unmarshal(data, (*T)(s))
}

<sub>NOTE: the temporary type T above is used to avoid a stack overflow caused by an infinite recursive call to the MarshalJSON and UnmarshalJSON methods.</sub>

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

huangapple
  • 本文由 发表于 2021年12月19日 00:15:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/70405042.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定