使用 unmarshal 从响应中获取特定的 JSON 字段

Posted

技术标签:

【中文标题】使用 unmarshal 从响应中获取特定的 JSON 字段【英文标题】:Using unmarshal to fetch specific JSON fields from response 【发布时间】:2014-04-26 22:29:10 【问题描述】:

我正在尝试使用他们的开放 API 获取特定 Subreddit 的热门提交列表:

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "os"
)

const api_endpoint = "http://www.reddit.com/r/%s/top.json?t=all&limit=100"

func main() 
    // Get console argument 'subreddit' and format the API endpoint URL.
    subreddit := os.Args[1]
    top_by_subreddit_endpoint := fmt.Sprintf(api_endpoint, subreddit)

    // Hit the API service.
    response, err := http.Get(top_by_subreddit_endpoint)
    if err != nil 
        //Perror(err)
     else 
        defer response.Body.Close()
        content, err := ioutil.ReadAll(response.Body)
        if err != nil 
            //Perror(err)
         else 
            var top_submissions Submission
            json.Unmarshal(content, &top_submissions)
        
    


type ByCreated []Submission

func (a ByCreated) Len() int            return len(a) 
func (a ByCreated) Swap(i, j int)       a[i], a[j] = a[j], a[i] 
func (a ByCreated) Less(i, j int) bool  return a[i].Created < a[j].Created 

type Submission struct 
    Domain              string `json:"domain"`
    BannedBy            string `json:"banned_by"`
    MediaEmbed          string `json:"media_embed"`
    Subreddit           string `json:"subreddit"`
    Selftexthtml        string `json:"selftext_html"`
    Selftext            string `json:"selftext"`
    Likes               bool   `json:"likes"`
    SecureMedia         string `json:"secure_media"`
    LinkFlairText       string `json:"link_flair_text"`
    Id                  string `json:"id"`
    Gilded              int    `json:"gilded"`
    SecureMediaEmbed    string `json:"secure_media_embed"`
    Clicked             bool   `json:"clicked"`
    Stickied            bool   `json:"stickied"`
    Author              string `json:"author"`
    Media               string `json:"media"`
    Score               int    `json:"score"`
    ApprovedBy          string `json:"approved_by"`
    Over18              bool   `json:"over_18"`
    Hidden              bool   `json:"hidden"`
    Thumbnail           string `json:"thumbnail"`
    SubredditId         string `json:"subreddit_id"`
    Edited              int    `json:"edited"`
    LinkFlairCssClass   string `json:"link_flair_css_class"`
    AuthorFlairCssClass string `json:"author_flair_css_class"`
    Downs               int    `json:"downs"`
    Saved               bool   `json:"saved"`
    IsSelf              bool   `json:"is_self"`
    Permalink           string `json:"permalink"`
    Name                string `json:"name"`
    Created             int    `json:"created"`
    Url                 string `json:"url"`
    AuthorFlairText     string `json:"author_flair_text"`
    Title               string `json:"title"`
    CreatedUtc          int    `json:"created_utc"`
    Ups                 int    `json:"ups"`
    NumComments         int    `json:"num_comments"`
    Visited             bool   `json:"visited"`
    NumReports          string `json:"num_reports"`
    Distinguished       string `json:"distinguished"`


不幸的是,这不起作用,因为actual submission list is nested inside the response。如何将数据 json 数组(位于 children 元素内)解组为 Submission 结构类型的数组?


    "kind": "Listing",
    "data": 
        "modhash": "1wcy5kngm9408522707f8e319ca825af342a5b3c460ca7c928",
        "children": [
            
                "kind": "t3",
                "data": 
                    "domain": "self.Smite",
                    "banned_by": null,
                    "media_embed": ,
                    "subreddit": "Smite",
                    "selftext_html": "&lt;!-- SC_OFF --&gt;&lt;div class=\"md\"&gt;&lt;p&gt;Hello Smite community - how&amp;#39;s it going? My name is Steve, but you can just call me Proto. I&amp;#39;m a forum moderator and content creator for Beyond Entertainment - a site which specializes in gaming news surrounding competitive console gaming and all around video games news. I&amp;#39;ve been around competitive gaming since 2007 back in the Halo 2 MLG days and have been hooked ever since. I&amp;#39;m not here to talk about myself though - and although I&amp;#39;m not a Smite player - I&amp;#39;m here to talk about a company who is becoming involved with the Smite community that goes by the name Bonafide Boarding &lt;a href=\"https://twitter.com/LiveBNFD\"&gt;https://twitter.com/LiveBNFD&lt;/a&gt;  &lt;/p&gt;\n\n&lt;p&gt;Now you might be asking yourself why am I writing this? First, these 2 tweets drew my attention in regards to Bonafide Boarding &lt;a href=\"https://twitter.com/BonafideBCC\"&gt;https://twitter.com/BonafideBCC&lt;/a&gt; - as well as Billy and Brad - working with people in the competitive Smite community  &lt;/p&gt;\n\n&lt;p&gt;&lt;a href=\"https://twitter.com/LiveBNFD/status/441044741699149825\"&gt;https://twitter.com/LiveBNFD/status/441044741699149825&lt;/a&gt;  &lt;/p&gt;\n\n&lt;p&gt;&lt;a href=\"https://twitter.com/HiRezNabil\"&gt;https://twitter.com/HiRezNabil&lt;/a&gt; (pictures with Brad under this Twitter user&amp;#39;s photos - Brad confirmed in the AGL Facebook cover photo as well just for verification)  &lt;/p&gt;\n\n&lt;p&gt;Well - I&amp;#39;m writing this because the owners of the Bonafide Boarding Clothing company, Brad Weir and Billy Lutz &lt;a href=\"https://twitter.com/MrBillyLutz\"&gt;https://twitter.com/MrBillyLutz&lt;/a&gt; have past experience in competitive gaming. including running their own league of Halo tournaments in 2012 and 2013. However, it&amp;#39;s not a good past - and to put it as blunt as possible - the two together are frauds who stole money from the Halo community and owe professional Halo players thousands of dollars from their Halo events - at the time known as AGL (Arena Gaming League) &lt;a href=\"https://www.facebook.com/ArenaGamingLeague\"&gt;https://www.facebook.com/ArenaGamingLeague&lt;/a&gt; (Brad Weir is in the cover photo, on the right, in the red t shirt interviewing the person on the left)  &lt;/p&gt;\n\n&lt;p&gt;Brad and Billy had their first AGL Halo event in August of 2012 - and in 2013 is when the problems began. While there is a lot more to talk about then what can be posted here, I will basically go into how AGL ended and how Halo players were scammed out of thousands of dollars in owed prize money - and to this day, no one has received any money from AGL, Brad or Billy for most of the 2013 AGL Halo tournaments.  &lt;/p&gt;\n\n&lt;p&gt;AGL had announced an event to held in Indianapolis, Indiana on November 1-3, 2013 called the &amp;quot;AGL 10K&amp;quot;. It was made out to be their biggest event yet - held at a brand new LAN center and promising the most prize money at any AGL event thus far at the time. However, just days before the event was scheduled to take place, it was cancelled as noted here with a direct quote from AGL/Brad in the article below  &lt;/p&gt;\n\n&lt;p&gt;&lt;a href=\"http://teambeyond.net/agl-10k-cancelled/\"&gt;http://teambeyond.net/agl-10k-cancelled/&lt;/a&gt;  &lt;/p&gt;\n\n&lt;p&gt;This also led to players not being able to get refunds for their team passes which many had already purchased for the event (note the dates on the tweets shown below)  &lt;/p&gt;\n\n&lt;p&gt;&lt;a href=\"https://twitter.com/jCreelz/status/394116351402737664\"&gt;https://twitter.com/jCreelz/status/394116351402737664&lt;/a&gt;  &lt;/p&gt;\n\n&lt;p&gt;&lt;a href=\"https://twitter.com/Ninja_Invictus/status/393922514247643136\"&gt;https://twitter.com/Ninja_Invictus/status/393922514247643136&lt;/a&gt;  &lt;/p&gt;\n\n&lt;p&gt;Not long after this event was cancelled, AGL completely shut down, seemingly out of nowhere - confirmed in this forum post by Brad himself on the Beyond Entertainment forums  &lt;/p&gt;\n\n&lt;p&gt;&lt;a href=\"http://teambeyond.net/forum/index.php?/topic/2238-agl-closes-down-statement/page-50?p=108159#entry108159\"&gt;http://teambeyond.net/forum/index.php?/topic/2238-agl-closes-down-statement/page-50?p=108159#entry108159&lt;/a&gt;  &lt;/p&gt;\n\n&lt;p&gt;Since AGL has shut down, there has been little to absolutely no contact from Brad, Billy, or anyone associated with AGL in terms of paying not only the professional players who are owed prize money, but commentators and staff from the event as well who were not paid and had no travel costs covered.  &lt;/p&gt;\n\n&lt;p&gt;The following are all tweets from professional Halo players who have still NEVER been paid by Brad Weir, Billy Lutz, or AGL as a whole.  &lt;/p&gt;\n\n&lt;p&gt;&lt;a href=\"https://twitter.com/MLGACE/statuses/408356773037232128\"&gt;https://twitter.com/MLGACE/statuses/408356773037232128&lt;/a&gt;  &lt;/p&gt;\n\n&lt;p&gt;&lt;a href=\"https://twitter.com/FormaL_tK/statuses/408400562372108288\"&gt;https://twitter.com/FormaL_tK/statuses/408400562372108288&lt;/a&gt;  &lt;/p&gt;\n\n&lt;p&gt;&lt;a href=\"https://twitter.com/Naded_MLG/statuses/426908120879607808\"&gt;https://twitter.com/Naded_MLG/statuses/426908120879607808&lt;/a&gt;  &lt;/p&gt;\n\n&lt;p&gt;&lt;a href=\"https://twitter.com/xPROVERBx/statuses/426975901583425536\"&gt;https://twitter.com/xPROVERBx/statuses/426975901583425536&lt;/a&gt;  &lt;/p&gt;\n\n&lt;p&gt;&lt;a href=\"https://twitter.com/enable_/status/426952260317220864\"&gt;https://twitter.com/enable_/status/426952260317220864&lt;/a&gt;  &lt;/p&gt;\n\n&lt;p&gt;&lt;a href=\"https://twitter.com/BRIZZ_Legit/status/426959849729974272\"&gt;https://twitter.com/BRIZZ_Legit/status/426959849729974272&lt;/a&gt;  &lt;/p&gt;\n\n&lt;p&gt;This recent tweet is also from someone who bought t shirts from Bonafide Boarding, Brad and Billy&amp;#39;s clothing company, and it appears they were screwed as well.  &lt;/p&gt;\n\n&lt;p&gt;&lt;a href=\"https://twitter.com/shellyteachesk2/status/447432597288017920\"&gt;https://twitter.com/shellyteachesk2/status/447432597288017920&lt;/a&gt;  &lt;/p&gt;\n\n&lt;p&gt;The reason I am writing all this is just to warn you guys as a community to not fall into the trap the Halo community fell into in 2013. Do not support these guys - and most importantly - do not give them your money. I have loved competitive gaming for a long time, and I want nothing more than to see it continue to grow. The last thing I want to see happen is what happened to the Halo community in 2013 at the hands of Brad Weir, Billy Lutz, and the AGL company as a whole. Brad, Billy, and Bonafide Boarding as a whole is nothing but a scam and these 2 owe a lot of people a lot of money. Hopefully you guys can take this to heart and not support these two scumbags who have still yet to pay thousands of dollars to people who rightfully won money in their tournaments. Thank you for reading.  &lt;/p&gt;\n\n&lt;ul&gt;\n&lt;li&gt;Proto&lt;/li&gt;\n&lt;/ul&gt;\n&lt;/div&gt;&lt;!-- SC_ON --&gt;",
                    "selftext": "Hello Smite community - how's it going? My name is Steve, but you can just call me Proto. I'm a forum moderator and content creator for Beyond Entertainment - a site which specializes in gaming news surrounding competitive console gaming and all around video games news. I've been around competitive gaming since 2007 back in the Halo 2 MLG days and have been hooked ever since. I'm not here to talk about myself though - and although I'm not a Smite player - I'm here to talk about a company who is becoming involved with the Smite community that goes by the name Bonafide Boarding https://twitter.com/LiveBNFD  \n\nNow you might be asking yourself why am I writing this? First, these 2 tweets drew my attention in regards to Bonafide Boarding https://twitter.com/BonafideBCC - as well as Billy and Brad - working with people in the competitive Smite community  \n\nhttps://twitter.com/LiveBNFD/status/441044741699149825  \n\nhttps://twitter.com/HiRezNabil (pictures with Brad under this Twitter user's photos - Brad confirmed in the AGL Facebook cover photo as well just for verification)  \n\nWell - I'm writing this because the owners of the Bonafide Boarding Clothing company, Brad Weir and Billy Lutz https://twitter.com/MrBillyLutz have past experience in competitive gaming. including running their own league of Halo tournaments in 2012 and 2013. However, it's not a good past - and to put it as blunt as possible - the two together are frauds who stole money from the Halo community and owe professional Halo players thousands of dollars from their Halo events - at the time known as AGL (Arena Gaming League) https://www.facebook.com/ArenaGamingLeague (Brad Weir is in the cover photo, on the right, in the red t shirt interviewing the person on the left)  \n\nBrad and Billy had their first AGL Halo event in August of 2012 - and in 2013 is when the problems began. While there is a lot more to talk about then what can be posted here, I will basically go into how AGL ended and how Halo players were scammed out of thousands of dollars in owed prize money - and to this day, no one has received any money from AGL, Brad or Billy for most of the 2013 AGL Halo tournaments.  \n\nAGL had announced an event to held in Indianapolis, Indiana on November 1-3, 2013 called the \"AGL 10K\". It was made out to be their biggest event yet - held at a brand new LAN center and promising the most prize money at any AGL event thus far at the time. However, just days before the event was scheduled to take place, it was cancelled as noted here with a direct quote from AGL/Brad in the article below  \n\nhttp://teambeyond.net/agl-10k-cancelled/  \n\nThis also led to players not being able to get refunds for their team passes which many had already purchased for the event (note the dates on the tweets shown below)  \n\nhttps://twitter.com/jCreelz/status/394116351402737664  \n\nhttps://twitter.com/Ninja_Invictus/status/393922514247643136  \n\nNot long after this event was cancelled, AGL completely shut down, seemingly out of nowhere - confirmed in this forum post by Brad himself on the Beyond Entertainment forums  \n\nhttp://teambeyond.net/forum/index.php?/topic/2238-agl-closes-down-statement/page-50?p=108159#entry108159  \n\nSince AGL has shut down, there has been little to absolutely no contact from Brad, Billy, or anyone associated with AGL in terms of paying not only the professional players who are owed prize money, but commentators and staff from the event as well who were not paid and had no travel costs covered.  \n\nThe following are all tweets from professional Halo players who have still NEVER been paid by Brad Weir, Billy Lutz, or AGL as a whole.  \n\nhttps://twitter.com/MLGACE/statuses/408356773037232128  \n\nhttps://twitter.com/FormaL_tK/statuses/408400562372108288  \n\nhttps://twitter.com/Naded_MLG/statuses/426908120879607808  \n\nhttps://twitter.com/xPROVERBx/statuses/426975901583425536  \n\nhttps://twitter.com/enable_/status/426952260317220864  \n\nhttps://twitter.com/BRIZZ_Legit/status/426959849729974272  \n\nThis recent tweet is also from someone who bought t shirts from Bonafide Boarding, Brad and Billy's clothing company, and it appears they were screwed as well.  \n\nhttps://twitter.com/shellyteachesk2/status/447432597288017920  \n\nThe reason I am writing all this is just to warn you guys as a community to not fall into the trap the Halo community fell into in 2013. Do not support these guys - and most importantly - do not give them your money. I have loved competitive gaming for a long time, and I want nothing more than to see it continue to grow. The last thing I want to see happen is what happened to the Halo community in 2013 at the hands of Brad Weir, Billy Lutz, and the AGL company as a whole. Brad, Billy, and Bonafide Boarding as a whole is nothing but a scam and these 2 owe a lot of people a lot of money. Hopefully you guys can take this to heart and not support these two scumbags who have still yet to pay thousands of dollars to people who rightfully won money in their tournaments. Thank you for reading.  \n\n- Proto",
                    "likes": true,
                    "secure_media": null,
                    "link_flair_text": null,
                    "id": "21dp8c",
                    "gilded": 0,
                    "secure_media_embed": ,
                    "clicked": false,
                    "stickied": false,
                    "author": "Proto__",
                    "media": null,
                    "score": 1038,
                    "approved_by": null,
                    "over_18": false,
                    "hidden": false,
                    "thumbnail": "",
                    "subreddit_id": "t5_2stl8",
                    "edited": 1395865323,
                    "link_flair_css_class": null,
                    "author_flair_css_class": null,
                    "downs": 274,
                    "saved": false,
                    "is_self": true,
                    "permalink": "/r/Smite/comments/21dp8c/a_warning_to_the_smite_community_bonafide/",
                    "name": "t3_21dp8c",
                    "created": 1395828838,
                    "url": "http://www.reddit.com/r/Smite/comments/21dp8c/a_warning_to_the_smite_community_bonafide/",
                    "author_flair_text": null,
                    "title": "A warning to the Smite community (Bonafide Boarding Clothing company)",
                    "created_utc": 1395800038,
                    "ups": 1312,
                    "num_comments": 200,
                    "visited": false,
                    "num_reports": null,
                    "distinguished": null
                
            ],
        
    

【问题讨论】:

【参考方案1】:

创建更多模拟 JSON 形状的结构(就像您的 Submission 结构)。解组为最顶层的结构之一,然后访问该结构的适当成员。

【讨论】:

我应该在问题中提到这一点,但我的最终目标是按其created 字段对提交进行排序。我想我可以将提交的数组从父结构复制到它自己的数组中 - 但我不想创建不必要的结构。 你无法避免额外的结构,但你最终应该得到一个 Listing 结构,其成员是 Submissions 的一部分,可以直接排序;无需复制切片。【参考方案2】:

你有 2 个问题。

    您的结构不正确,MediaEmbedMediaSecureMediaSecureMediaEmbed 可以是对象而不是字符串,Edited 可以是“假”,日期是浮点数而不是整数。

    你必须使用额外的结构,但你可以嵌入它们。

例子:

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "os"
    "sort"
)

const (
    api_endpoint = "http://www.reddit.com/r/%s/top.json?t=all&limit=100"
)

func main() 
    var top_submissions struct 
        Kind interface
        Data struct 
            ModHash  interface
            Children []struct 
                Kind interface
                Data Submission
            
            After  string
            Before interface
        
    

    subreddit := os.Args[1]
    top_by_subreddit_endpoint := fmt.Sprintf(api_endpoint, subreddit)

    // Hit the API service.
    response, err := http.Get(top_by_subreddit_endpoint)
    if err != nil 
        panic(err)
     else 
        defer response.Body.Close()
        content, err := ioutil.ReadAll(response.Body)
        if err != nil 
            //Perror(err)
         else 
            if err := json.Unmarshal(content, &top_submissions); err != nil 
                panic(err)
            
        
    
    byCreated := make(ByCreated, len(top_submissions.Data.Children))
    for i, v := range top_submissions.Data.Children 
        byCreated[i] = v.Data
    

    sort.Sort(byCreated)
    for _, v := range byCreated 
        fmt.Printf("%#v\n", v)
    


type ByCreated []Submission

func (a ByCreated) Len() int            return len(a) 
func (a ByCreated) Swap(i, j int)       a[i], a[j] = a[j], a[i] 
func (a ByCreated) Less(i, j int) bool  return a[i].Created < a[j].Created 

type Submission struct 
    Domain              string          `json:"domain"`
    BannedBy            string          `json:"banned_by"`
    MediaEmbed          json.RawMessage `json:"media_embed"`
    Subreddit           string          `json:"subreddit"`
    SelftextHtml        string          `json:"selftext_html"`
    Selftext            string          `json:"selftext"`
    Likes               bool            `json:"likes"`
    SecureMedia         json.RawMessage `json:"secure_media"`
    LinkFlairText       string          `json:"link_flair_text"`
    Id                  string          `json:"id"`
    Gilded              int             `json:"gilded"`
    SecureMediaEmbed    json.RawMessage `json:"secure_media_embed"`
    Clicked             bool            `json:"clicked"`
    Stickied            bool            `json:"stickied"`
    Author              string          `json:"author"`
    Media               json.RawMessage `json:"media"`
    Score               int             `json:"score"`
    ApprovedBy          string          `json:"approved_by"`
    Over18              bool            `json:"over_18"`
    Hidden              bool            `json:"hidden"`
    Thumbnail           string          `json:"thumbnail"`
    SubredditId         string          `json:"subreddit_id"`
    Edited              interface     `json:"edited"` //this can be false
    LinkFlairCssClass   string          `json:"link_flair_css_class"`
    AuthorFlairCssClass string          `json:"author_flair_css_class"`
    Downs               int             `json:"downs"`
    Saved               bool            `json:"saved"`
    IsSelf              bool            `json:"is_self"`
    Permalink           string          `json:"permalink"`
    Name                string          `json:"name"`
    Created             float32         `json:"created"`
    Url                 string          `json:"url"`
    AuthorFlairText     string          `json:"author_flair_text"`
    Title               string          `json:"title"`
    CreatedUtc          float32         `json:"created_utc"`
    Ups                 int             `json:"ups"`
    NumComments         int             `json:"num_comments"`
    Visited             bool            `json:"visited"`
    NumReports          string          `json:"num_reports"`
    Distinguished       string          `json:"distinguished"`

【讨论】:

以上是关于使用 unmarshal 从响应中获取特定的 JSON 字段的主要内容,如果未能解决你的问题,请参考以下文章

XML解析器(Unmarshal)使用JaxB从xml文件中获取元素

使用 JAXB 和 Unmarshal 过早结束文件。响应中的 xml 对我来说似乎有效

在 Unmarshal 期间处理不同类型的参数

如何从 JSON 对象中获取特定的键值

C# 使用 HttpClient 从 JSON 响应中获取特定对象

如何从响应中获取特定字段 - 在自动完成的 getOptionLabel 中设置