-
Notifications
You must be signed in to change notification settings - Fork 1k
Any_cn
English | 中文
很多情况下,对于一个json输入源,我们只对其部分内容感兴趣。为了得到我们需要的小部分信息,去定义跟这个json串匹配的schema是一件麻烦的事件。对于体积庞大或者嵌套层次深的json串尤其如此。json-iterator提供了Any
对象,可以很方便地从json串中获取你想要的元素,而不需要去定义schema
假设我们有这么一个json
jsonStr := []byte(`{
"users": [
{
"username": "system",
"avatar_template": "/user_avatar/discourse.metabase.com/system/{size}/6_1.png",
"id": -1
},
{
"username": "zergot",
"avatar_template": "https://avatars.discourse.org/v2/letter/z/0ea827/{size}.png",
"id": 89
}
],
"topics": {
"can_create_topic": false,
"more_topics_url": "/c/uncategorized/l/latest?page=1",
"draft": null,
"draft_key": "new_topic",
"draft_sequence": null,
"per_page": 30,
"topics": [
{
"bumped": true,
"id": 8,
"excerpt": "Welcome to Metabase\u0026#39;s discussion forum. This is a place to get help on installation, setting up as well as sharing tips and tricks.",
"category_id": 1,
"unseen": false,
"slug": "welcome-to-metabases-discussion-forum",
"fancy_title": "Welcome to Metabase\u0026rsquo;s Discussion Forum",
"bookmarked": null,
"archived": false,
"archetype": "regular",
"highest_post_number": 1,
"reply_count": 0,
"visible": true,
"closed": false,
"liked": null,
"posts_count": 1,
"views": 197,
"image_url": "/images/welcome/discourse-edit-post-animated.gif",
"created_at": "2015-10-17T00:14:49.526Z",
"last_posted_at": "2015-10-17T00:14:49.557Z",
"pinned": true,
"title": "Welcome to Metabase's Discussion Forum",
"has_summary": false,
"like_count": 0,
"pinned_globally": true,
"last_poster_username": "system",
"posters": [
{
"extras": "latest single",
"description": "Original Poster, Most Recent Poster", // 我们需要这个
"user_id": -1
}
],
"bumped_at": "2015-10-21T02:32:22.486Z",
"unpinned": null
}
]
}
}`)
如果用传统的方法,那么首先我们应该先定义一个匹配这个json结构的结构体,然后调用Unmarshal
来反序列化,再获取这个结构体中我们需要的字段的值。如果用Any
,那么就很简单了:
any := jsoniter.Get(jsonStr, "topics", "topics", 0, "posters", 0, "description")
fmt.Println(any.ToString())
// Output:
// Original Poster, Most Recent Poster
只需要一行,我们就可以拿到我们想要的元素。然后调用Any
对象提供的接口做下转换,就得到了我们要的description字符串
还是上面的例子
jsonStr := []byte(`{
"users": [
{
"username": "system",
"avatar_template": "/user_avatar/discourse.metabase.com/system/{size}/6_1.png",
"id": -1
},
{
"username": "zergot",
"avatar_template": "https://avatars.discourse.org/v2/letter/z/0ea827/{size}.png",
"id": 89
}
],
"topics": {
"can_create_topic": false,
"more_topics_url": "/c/uncategorized/l/latest?page=1",
"draft": null,
"draft_key": "new_topic",
"draft_sequence": null,
"per_page": 30,
"topics": [
{
"bumped": true,
"id": 8,
"excerpt": "Welcome to Metabase\u0026#39;s discussion forum. This is a place to get help on installation, setting up as well as sharing tips and tricks.",
"category_id": 1,
"unseen": false,
"slug": "welcome-to-metabases-discussion-forum",
"fancy_title": "Welcome to Metabase\u0026rsquo;s Discussion Forum",
"bookmarked": null,
"archived": false,
"archetype": "regular",
"highest_post_number": 1,
"reply_count": 0,
"visible": true,
"closed": false,
"liked": null,
"posts_count": 1,
"views": 197,
"image_url": "/images/welcome/discourse-edit-post-animated.gif",
"created_at": "2015-10-17T00:14:49.526Z",
"last_posted_at": "2015-10-17T00:14:49.557Z",
"pinned": true,
"title": "Welcome to Metabase's Discussion Forum",
"has_summary": false,
"like_count": 0,
"pinned_globally": true,
"last_poster_username": "system",
"posters": [
{ // 这次我们需要这个
"extras": "latest single",
"description": "Original Poster, Most Recent Poster",
"user_id": -1
}
],
"bumped_at": "2015-10-21T02:32:22.486Z",
"unpinned": null
}
]
}
}`)
这次我们需要"posters"数组的第一个结构体,我们现在已经有它的schema定义了,除此之外这个json的其他信息我都不需要,那么如何通过Any
对象获得这个结构体呢?我们需要ToVal
接口:
type Poster struct {
Extras string `json:"extras"`
Desc string `json:"description"`
UserId int `json:"user_id"`
}
var p Poster
any := jsoniter.Get(jsonStr, "topics", "topics", 0, "posters", 0)
any.ToVal(&p)
fmt.Printf("extras=%s\ndescription=%s\nuser_id=%d\n", p.Extras, p.Desc, p.UserId)
// Output:
// extras=latest single
// description=Original Poster, Most Recent Poster
// user_id=-1
这里可以看到,首先我们拿到了"posters"第一个元素的Any
对象,然后调用ToVal
方法,就可以像之前的反序列化方法一样把数据解析出来。实际上,如果你的Any
对象对应的是数组或对象类型的元素,它内部保存了这个元素原始的json串。当你需要获取其字段、元素或者将其反序列化出来的时候,才会触发解析。json-iterator内部将其称为懒解析。来看个数组的例子:
type User struct {
UserName string `json:"username"`
Template string `json:"avatar_template"`
Id int `json:"id"`
}
var users []User
any := jsoniter.Get(jsonStr, "users")
fmt.Println(any.Get(0, "username").ToString())
// Output:
// system
any.ToVal(&users)
fmt.Printf("username=%s\navatar_template=%s\nid=%d\n", users[1].UserName, users[1].Template, users[1].Id)
// Output:
// username=zergot
// avatar_template=https://avatars.discourse.org/v2/letter/z/0ea827/{size}.png
// id=89
数组元素的获取方法其实也是类似,这里不再详述。
有一点需要说明的是,只有数组和对象的json元素对应的Any
才提供ToVal
方法,也就是说这两种json元素的Any
对象才实现了懒解析,其他诸如int
,bool
,string
等都没有实现,实际上它们也不需要什么懒解析