我在将一个JSON文件从API解析为Go时遇到了一些问题,这是我要解析的JSON:
{"method":"stats.provider.ex",
"result":{
"addr":"17a212wdrvEXWuipCV5gcfxdALfMdhMoqh",
"current":[{
"algo":3, // algorithm number (3 = X11)
"name":"X11", // algorithm name
"suffix":"MH", // speed suffix (kH, MH, GH, TH,...)
"profitability":"0.00045845", // current profitability in BTC/suffix/Day
"data":[{ // speed object can contain following fields:
// a (accepted), rt (rejected target), rs (rejected stale),
// rd (rejected duplicate) and ro (rejected other)
// if fields are not present, speed is 0
"a":"23.09", // accepted speed (in MH/s for X11)
"rs":"0.54", // rejected speed - stale
},
"0.0001234" // balance (unpaid)
]},
... // other algorithms here
],
"past":[{
"algo":3,
"data":[
[4863234, // timestamp; multiply with 300 to get UNIX timestamp
{"a":"28.6"}, // speed object
"0" // balance (unpaid)
],[4863235,{"a":"27.4"},"0.00000345"],
... // next entries with inc. timestamps
]},
... // other algorithms here
],
"payments":[{
"amount":"0.00431400",
"fee":"0.00023000",
"TXID":"txidhere",
"time":1453538732, // UNIX timestamp
"type":0 // payment type (0 for standard NiceHash payment)
},
... // other payments here
]
}
}
您可以在此链接中找到有关API的更多信息:https://www.nicehash.com/doc-api
我遇到的问题出在数据属性中:
"data":[{ // speed object can contain following fields:
// a (accepted), rt (rejected target), rs (rejected stale),
// rd (rejected duplicate) and ro (rejected other)
// if fields are not present, speed is 0
"a":"23.09", // accepted speed (in MH/s for X11)
"rs":"0.54", // rejected speed - stale
},
"0.0001234" // balance (unpaid)
]},
由于余额(未支付)行,因为它没有名称,所以我不知道如何进行结构化。
答案 0 :(得分:3)
似乎这个"数据" object可以用以下结构类型来描述(假设它的形状与你的例子不同):
type Data struct {
Timestamp *int64
Speed *Speed
Balance *float64
}
type Speed struct {
Accepted *float64 `json:"a,string,omitempty"`
RejectedTarget *float64 `json:"rt,string,omitempty"`
RejectedStale *float64 `json:"rs,string,omitempty"`
RejectedDuplicate *float64 `json:"rd,string,omitempty"`
RejectedOther *float64 `json:"ro,string,omitempty"`
}
"速度" struct具有JSON标记,因为该对象非常适合默认的JSON un / marshaler。
"数据"但是,struct应该实现一个自定义json.UnmarshalJSON
,以便它可以处理具有不同类型的JSON数组的奇怪选择,以序列化其字段。请注意,下面的示例实现使用json.RawMessage
type来简化一些事情,允许JSON解组器确保正确的JSON数组语法并分别存储每个元素的字节,以便我们可以根据它们各自的类型和形状解组它们:
// Parse valid JSON arrays as "Data" by assuming one of the following shapes:
// 1: [int64, Speed, string(float64)]
// 2: [Speed, string(float64)]
func (d *Data) UnmarshalJSON(bs []byte) error {
// Ensure that the bytes contains a valid JSON array.
msgs := []json.RawMessage{}
err := json.Unmarshal(bs, &msgs)
if err != nil {
return err
}
// Parse the initial message as "Timestamp" int64, if necessary.
idx := 0
if len(msgs) == 3 {
ts, err := strconv.ParseInt(string(msgs[idx]), 10, 64)
if err != nil {
return err
}
d.Timestamp = &ts
idx++
}
// Parse the mandatory "Speed" struct per usual.
d.Speed = &Speed{}
err = json.Unmarshal(msgs[idx], &d.Speed)
idx++
if err != nil {
return err
}
// Parse the mandatory "Balance" item after trimming quotes.
balance, err := strconv.ParseFloat(string(msgs[idx][1:len(msgs[idx])-1]), 64)
if err != nil {
return err
}
d.Balance = &balance
return nil
}
因此,您可以将有效,形状正确的JSON数组解析为" Data"像这样的对象:
jsonstr := `[
[4863234, {"a":"28.6"}, "0" ],
[{"a":"23.09","rs":"0.54"},"0.0001234"]
]`
datas := []Data{}
err := json.Unmarshal([]byte(jsonstr), &datas)
if err != nil {
panic(err)
}
// datas[0] = Data{Timestamp:4863234,Speed{Accepted:28.6},Balance:0}
// datas[1] = Data{Speed{Accepted:23.09,RejectedStale:0.54},Balance:0.0001234}
当然,如果你想序列化数据"你还需要实现json.MarshalJSON
。将对象转换为JSON。
答案 1 :(得分:1)
JSON对象中的data
字段有一个数组[…]
作为其值,和
在您的示例中,该数组有两个元素:一个对象和一个显然包含浮点数的字符串。
如您所见,这是一系列geterogenous类型, 因此在Go中,您有两种选择:
为该数组的元素创建自定义类型,并具有
该类型实现encoding/json.Unmarshaler
接口。
然后,在那种方法中,你可以创造性地解释什么
您要解组的数据类型,并采取相应的行动。
基本上,您可以使用Decoder.Token
然后查看输入数据
将整个输入字节切片解组为适当类型的值
将该data
字段的值解组为a
切片类型[]interface{}
,然后检查各个元素
通过type switch
或一系列“逗号ok”类型断言。
在这种情况下,对象将被解组为类型的地图
map[string]interface{}
,该字符串将被解组
值为string
的值。
基本上这两种方法可归类为“随时检测类型” vs“将所有内容解组为最通用类型的数据结构 然后处理真正的打字“。
这也是第三种方法。
首先,可能会发现数组中的对象类型
这个data
字段的值是从它们的位置隐含的
在数组中。您可以通过解组data
的值来相应地采取行动
进入实现json.Unmarshaler
的自定义类型的对象,其中
知道这是它处理的每个数据元素的真实类型。
其次,从
开始{
// speed object can contain following fields:
// a (accepted), rt (rejected target), rs (rejected stale),
// rd (rejected duplicate) and ro (rejected other)
// if fields are not present, speed is 0
"a":"23.09", // accepted speed (in MH/s for X11)
"rs":"0.54", // rejected speed - stale
}
我会说这个“对象”真的可以有不同的字段组合,
所以对我来说,这看起来像是一个被解散的候选人
进入map[string]string
或map[string]float
,
而不是某些struct
类型的对象。