2014-07-16 68 views
12
多个JSON表示

我试图解决的问题是,我有一个社区,看起来像这样一个结构与Golang

type Community struct { 
    Name string 
    Description string 
    Sources []Source 
    Popularity int 
    FavoriteCount int 
    Moderators []string 
    Children []Community 
    Tracks []Track 
} 

社区持有大量的信息模型,并有场景时我只想返回部分描述,例如,如果我要返回趋势社区列表。在这种情况下,我只想返回

type Community struct { 
    Name string 
    Description string 
    Popularity int 
    FavoriteCount int 
} 

我能想到这样做是为了创建一个仅包含那些字段的新类型,写一个便捷方法,它需要一个社区,并返回该类型的唯一方法,但实质上创建一个新的对象,并按价值复制这些字段,有没有更好的方法来做到这一点?

我知道json:"-"的语法,但我不确定你是如何做到这一点的情况下,因为我仍然需要有时返回完整的对象,也许是一种不同的类型,被类型化为?

+0

一种可能的方式是实现一个自定义http://golang.org/pkg/encoding/json/#Marshaler连同内部配置字段中指定你想要发出的结构的哪些字段 –

回答

2

我开发了一个库,它可以帮助你在这方面:Sheriff

您可以用特殊的标记注释你的结构域和谢里夫打电话给定结构转化为它的一个子集。之后,您可以拨打json.Marshal()或其他任何您想要编入的内容。

为你的榜样将变得非常简单:

type Community struct { 
    Name   string  `json:"name" groups:"trending,detail"` 
    Description string  `json:"description" groups:"trending,detail"` 
    Sources  []Source `json:"sources" groups:"detail"` 
    Popularity int   `json:"popularity" groups:"trending,detail"` 
    FavoriteCount int   `json:"favorite_count" groups:"trending,detail"` 
    Moderators []string `json:"moderators" groups:"detail"` 
    Children  []Community `json:"children" groups:"detail"` 
    Tracks  []Track  `json:"tracks" groups:"detail"` 
} 

communities := []Community{ 
    // communities 
} 

o := sheriff.Options{ 
    Groups: []string{"trending"}, 
} 

d, err := sheriff.Marshal(&o, communities) 
if err != nil { 
    panic(err) 
} 

out, _ := json.Marshal(d) 
3

是的,据我所知,使用默认的Marshaller是唯一的方法。唯一的另一种选择是如果你创建你自己的JsonMarshaller。

type Community struct { 

} 

type CommunityShort Community 

func (key *Community) MarshalJSON() ([]byte, os.Error) { 
    ... 
} 

func (key *Community) UnmarshalJSON(data []byte) os.Error { 
... 
} 


func (key *CommunityShort) MarshalJSON() ([]byte, os.Error) { 
    ... 
} 

func (key *CommunityShort) UnmarshalJSON(data []byte) os.Error { 
... 
} 
12

编辑我的答案 - 找到一个更好的办法:

这是一个很酷的方法:

http://attilaolah.eu/2014/09/10/json-and-struct-composition-in-go/

涉及到创建一种屏蔽结构的。

这里的文章中的例子:

type User struct { 
    Email string `json:"email"` 
    Password string `json:"password"` 
    // many more fields… 
} 

type omit *struct{} 

type PublicUser struct { 
    *User 
    Password omit `json:"password,omitempty"` 
} 

// when you want to encode your user: 
json.Marshal(PublicUser{ 
    User: user, 
}) 
2

我将介绍你,我已经开发了另一种方法。我认为它更干净。唯一的缺点是稍微复杂的对象初始化,但在使用中它非常简化。

主要的一点是,你不是原来的对象上立足的JSON-视图对象,然后在里面隐藏元素,但周围的其他方法,使得它的原始对象的一部分:

type CommunityBase struct { 
    Name string 
    Description string 
} 

type Community struct { 
    CommunityBase 
    FavoriteCount int 
    Moderators []string 
} 

var comm = Community{CommunityBase{"Name", "Descr"}, 20, []string{"Mod1","Mod2"}} 

json.Marshal(comm) 
//{"Name":"Name","Description":"Descr","FavoriteCount":20,"Moderators":["Mod1","Mod2"]} 

json.Marshal(comm.CommunityBase) 
//{"Name":"Name","Description":"Descr"} 

这就是所有如果您只需要一个视图,或者如果您的意见逐步扩大。

但是如果你的意见不能被继承,你将不得不求助于一种混入的,这样就可以使他们从一个组合视图:

type ThingBaseMixin struct { 
    Name string 
} 

type ThingVisualMixin struct { 
    Color string 
    IsRound bool 
} 

type ThingTactileMixin struct { 
    IsSoft bool 
} 

type Thing struct { 
    ThingBaseMixin 
    ThingVisualMixin 
    ThingTactileMixin 
    Condition string 
    visualView *ThingVisualView 
    tactileView *ThingTactileView 
} 

type ThingVisualView struct { 
    *ThingBaseMixin 
    *ThingVisualMixin 
} 

type ThingTactileView struct { 
    *ThingBaseMixin 
    *ThingTactileMixin 
} 

func main() { 
    obj := Thing { 
     ThingBaseMixin: ThingBaseMixin{"Bouncy Ball"}, 
     ThingVisualMixin: ThingVisualMixin{"blue", true}, 
     ThingTactileMixin: ThingTactileMixin{false}, 
     Condition: "Good", 
    } 
    obj.visualView = &ThingVisualView{&obj.ThingBaseMixin, &obj.ThingVisualMixin} 
    obj.tactileView = &ThingTactileView{&obj.ThingBaseMixin, &obj.ThingTactileMixin} 

    b, _ := json.Marshal(obj) 
    fmt.Println(string(b)) 
//{"Name":"Bouncy Ball","Color":"blue","IsRound":true,"IsSoft":false,"Condition":"Good"} 

    b, _ = json.Marshal(obj.ThingVisualMixin) 
    fmt.Println(string(b)) 
//{"Color":"blue","IsRound":true} 

    b, _ = json.Marshal(obj.visualView) 
    fmt.Println(string(b)) 
//{"Name":"Bouncy Ball","Color":"blue","IsRound":true} 

    b, _ = json.Marshal(obj.tactileView) 
    fmt.Println(string(b)) 
//{"Name":"Bouncy Ball","IsSoft":false} 
} 

在这里,我增加了一个图到对象,但如果你喜欢,你可以打电话Marshal只是当创建它:

json.Marshal(ThingVisualView{&obj.ThingBaseMixin, &obj.ThingVisualMixin}) 

甚至没有一个初步的类型声明:

json.Marshal(struct{*ThingBaseMixin;*ThingVisualMixin}{&obj.ThingBaseMixin,&obj.ThingVisualMixin}) 
+0

这是一个非常有趣的方法。您的回复的第二部分以某种方式让我想起了PHP特性。 –

+0

有趣的是,您可以直接通过视图编辑原始对象。也许这种方法也可以用于其他领域。 – user