在Go Lang中解析JSON:没有名称的属性

时间:2017-12-26 16:51:43

标签: json go

我在将一个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)
    ]},

由于余额(未支付)行,因为它没有名称,所以我不知道如何进行结构化。

2 个答案:

答案 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]stringmap[string]float, 而不是某些struct类型的对象。

相关问题