英文:
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 的 map
或 struct
类型。此外,它还可以将任何 JSON 值解组为空的 interface{}
。
还要注意,Go 是一种静态类型语言,如果你将一个值指定为 T1
类型,那么在运行时,你无法将其类型更改为 T2
。没有办法做到这一点,无法更改值的类型。
因此,如果你将一个字段定义为某个 struct
类型,你不能默认情况下将 JSON 字符串解组为它。同样,如果你将一个字段定义为 string
类型,你不能默认情况下将 JSON 对象解组为它。
但是,由于 JSON 本身允许动态结构,encoding/json
包提供了两个接口,使你能够自定义 JSON 的编组和解组方式。
因此,如果你有一个 JSON 属性(例如 "balance"
或 "nonce"
),它可以是 "="
(一个字符串)或 { ... }
(一个对象),你需要声明一个自定义类型,实现 json.Marshaler
和 json.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
用于避免由于对 MarshalJSON
和 UnmarshalJSON
方法的无限递归调用而导致的堆栈溢出。</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. "balance"
or "nonce"
) that can be either "="
(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:"*"`
}
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))
}
<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>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论