go json 解组选项

go json unmarshal options

试图找到一个简单的解决方案 marshaling/unmashaling 到以下结构

type Resource struct {
    Data []ResourceData `json:"data"`
}
type ResourceData struct {
    Id string  `json:"id"`
    Type string  `json:"type"`
    Attributes map[string]interface{} `json:"attributes"`
    Relationships map[string]Resource `json:"relationships"`
}
r := Resource{}
json.Unmarshal(body, &r)

这很棒,如果:

body = `{"data":[{"id":"1","type":"blah"}]}`

但是我还需要它来回复:

body = `{"data":{"id":"1","type":"blah"}}` //notice no slice

我可以做一个单独的类型

type ResourceSingle struct {
    Data ResourceData `json:"data"`
}

但是,这意味着需要复制我附加到资源的所有功能,这是可能的。但是,我需要在执行它之前找出要解组的类型,再加上关系部分,每个都可能包含数据:[]{} 或数据{},所以这个想法不会工作。

或者我可以使用

map[string]*json.RawMessage
//or
type Resource struct {
    Data *json.RawMessage `json:"data"`
}

但是,当处于 json 形式时,我如何知道它是一个切片还是一个节点来提供正确的结构来解组?

我最后的办法是将 umarshal 映射到[string]接口并使用大量反射测试..但这是非常冗长的。

想法?

亲切的问候,jJ

有多种构造它的方法,但最简单的技术归结为实现 json.Unmarshaler 并检查数据类型。您可以最低限度地解析 json 字节,通常只是第一个字符,或者您可以尝试解组为每种类型和 return 成功的类型。

我们将在这里使用后一种技术,无论传入数据的格式如何,都将 ResourceData 插入到切片中,因此我们始终可以以相同的方式对其进行操作:

type Resource struct {
    Data []ResourceData
}

func (r *Resource) UnmarshalJSON(b []byte) error {
    // this gives us a temporary location to unmarshal into
    m := struct {
        DataSlice struct {
            Data []ResourceData `json:"data"`
        }
        DataStruct struct {
            Data ResourceData `json:"data"`
        }
    }{}

    // try to unmarshal the data with a slice
    err := json.Unmarshal(b, &m.DataSlice)
    if err == nil {
        log.Println("got slice")
        r.Data = m.DataSlice.Data
        return nil
    } else if err, ok := err.(*json.UnmarshalTypeError); !ok {
        // something besides a type error occurred
        return err
    }

    // try to unmarshal the data with a struct
    err = json.Unmarshal(b, &m.DataStruct)
    if err != nil {
        return err
    }
    log.Println("got struct")

    r.Data = append(r.Data, m.DataStruct.Data)
    return nil
}

http://play.golang.org/p/YIPeYv4AfT