去json unmarshal选项 [英] go json unmarshal options

查看:123
本文介绍了去json unmarshal选项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

试图找到一个简单的解决方案来封送/ unmashaling到下面的结构中:

  type Resource struct {
Data [] ResourceData`json:data`
}
类型ResourceData结构{
Id字符串`json:id`
类型字符串`json:type`
属性map [string] interface {}`json:attributes`
关系map [string]资源`json:relationships`
}
r:= Resource {}
json.Unmarshal(body,& r)

这很好,如果:

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

不过,我也需要回应:

  body =`{data:{id:1,type:blah}}`//注意没有切片

我可以创建一个单独的类型

 类型ResourceSingle struct {
Data ResourceData`json:data`
}

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



或者我可以使用

  map [string] * json.RawMessage 
//或
类型资源结构{
Data * json.RawMessage`json:data`
}

但是,如果以json的形式表达,我怎么知道它是一个片段还是一个节点来提供正确的解构结构?



我最后的手段是将umarshal放入map [string]接口并使用大量的反射测试..但是这是非常长的时间。



想法?



亲切的问候,jJ

解决方案

有很多方法来构造它,但最简单的技术归结为实现 json.Unmarshaler ,并检查数据的类型。您可以最小化解析json字节,通常只是第一个字符,或者您可以尝试解组到每个类型并返回成功。



我们将使用后一种技术,并将ResourceData插入切片,而不管输入数据的格式如何,所以我们可以始终以相同的方式对它进行操作:

 类型资源结构{
Data [] ResourceData
}

func(r * Resource)UnmarshalJSON(b []字节)错误{
//这给了我们一个临时的位置以解密为
m:= struct {
DataSlice struct {
Data [] ResourceData`json:data`
}
DataStruct struct {
Data ResourceData`json:data`
}
} {}

//尝试用片段解组数据
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 {
//除了发生类型错误之外的其他东西
return err
}

//尝试使用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


Trying to find a simple solution to marshaling/unmashaling into the following struct

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)

this is great if:

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

However I also need it to respond to:

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

I could make a separate type

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

However, that would mean needing to duplicate all the functions I have attached to resource, which is possible. However, i would need to find out which type to unmarshal into before executing it, plus when it comes to the relationships part, each of those could contain data:[]{} or data{}, so that idea isn't going to work.

Alternatively I could use

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

but still, when in json form how do I know if it is a slice or a node to supply the correct struct to unmarshal into?

My last resort is to umarshal into map[string]interface and use lots of reflect testing .. but this is very long winded.

Ideas?

Kind regards, jJ

解决方案

There's a number of ways to structure it, but the simplest technique comes down to implementing a json.Unmarshaler, and inspecting the type of the data. You can minimally parse the json bytes, often just the first character, or you can try to unmarshal into each type and return the one that succeeds.

We'll use the latter technique here, and insert the ResourceData into a slice regardless of the incoming data's format, so we can always operate on it in the same manner:

type Resource struct {
    Data []ResourceData
}

func (r *Resource) UnmarshalJSON(b []byte) error {
    // this gives us a temporary location to unamrshal 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 unamrshal 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

这篇关于去json unmarshal选项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆