Go:解析嵌套对象数组的JSON

huangapple go评论82阅读模式
英文:

Go: Unmarshal JSON nested array of objects

问题

我知道你可以将任意的JSON解组成map[string]interface{}值,虽然这样可以工作,但是我的JSON响应总是被定义和一致的,为了简单起见,我更喜欢将其解组成嵌套的结构体。

这是一个简化的JSON响应示例:

{
  "results": [
    {
      "section": "N.Y. / Region",
      "subsection": "",
      "title": "Christie Spins His Version of Security Record on Trail",
      "abstract": "An examination of Gov. Chris Christie’s record as New Jersey’s top federal prosecutor shows that he has, at times, overstated the significance of the terrorism prosecutions he oversaw.",
      "url": "http://www.nytimes.com/2015/12/27/nyregion/Christie-markets-himself-as-protector-to-gain-in-polls.html",
      "byline": "By ALEXANDER BURNS and CHARLIE SAVAGE",
      "item_type": "Article",
      "updated_date": "2015-12-26T18:04:19-5:00",
      "multimedia": [
        {
          "url": "http://static01.nyt.com/images/2015/12/27/nyregion/27CHRISTIE1/27CHRISTIE1-thumbStandard.jpg",
          "format": "Standard Thumbnail",
          "height": 75,
          "width": 75,
          "type": "image",
          "subtype": "photo",
          "caption": "Gov. Chris Christie of New Jersey spoke about the Sept. 11, 2001, attacks at a Republican conference last month.",
          "copyright": "Stephen Crowley/The New York Times"
        }
        ...
      ]
    }
  ]
}

我尝试过的方法

我尝试使用JSONutils来自动生成结构体,最终得到了以下结果(删除了我不需要的字段):

package main

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

type PoliticsJson struct {
	Results []struct {
		Multimedia []struct {
			URL string `json:"url"`
		} `json:"multimedia"`
		Title string `json:"title"`
	} `json:"results"`
}

func retrieveData() []byte {
	url := "http://api.nytimes.com/svc/topstories/v1/politics.json?MYAPIKEY"
	resp, err := http.Get(url)
	if err != nil {
		fmt.Println(err)
	}
	defer resp.Body.Close()
	body, err2 := ioutil.ReadAll(resp.Body)
	if err2 != nil {
		fmt.Println(err2)
	}
	return body
}

func main() {
	var p PoliticsJson

	err := json.Unmarshal(retrieveData(), &p)
	if err != nil {
		panic(err)
	}
	fmt.Println(p.Results[0].Title)
}

我只是想打印出最后一个multimedia数组中对象的标题和URL。(我只是想让它能够工作,所以请原谅我的错误处理。)

这是我得到的错误:panic: json: cannot unmarshal string into Go value of type []struct { URL string "json:\"url\"" }

问题显然出现在Multimedia结构体中。让我困惑的是,这个错误似乎表明它被解释为一个字符串,但是我更改了结构体以确保它是这样的:

type PoliticsJson struct {
	Results []struct {
		Multimedia string `json:"multimedia"`
		Title      string `json:"title"`
	} `json:"results"`
}

然后我得到了panic: json: cannot unmarshal array into Go value of type string,这表明它在JSON中被解释为一个数组。

再次强调,我只是想打印出最后一个multimedia数组中对象的标题和URL。

英文:

I'm aware that you can unmarshal arbitrary JSON into a map[string]interface{} value, and while that works, my JSON response is always defined and consistent, and for simplicity's sake, I'd prefer to unmarshal it as nested structs.

Here's a sample of the JSON response, abbreviated:

{
  (...)
  "results": [
    {
      "section": "N.Y. / Region",
      "subsection": "",
      "title": "Christie Spins His Version of Security Record on Trail",
      "abstract": "An examination of Gov. Chris Christie’s record as New Jersey’s top federal prosecutor shows that he has, at times, overstated the significance of the terrorism prosecutions he oversaw.",
      "url": "http://www.nytimes.com/2015/12/27/nyregion/Christie-markets-himself-as-protector-to-gain-in-polls.html",
      "byline": "By ALEXANDER BURNS and CHARLIE SAVAGE",
      "item_type": "Article",
      "updated_date": "2015-12-26T18:04:19-5:00",
      (...)
      "multimedia": [
        {
          "url": "http://static01.nyt.com/images/2015/12/27/nyregion/27CHRISTIE1/27CHRISTIE1-thumbStandard.jpg",
          "format": "Standard Thumbnail",
          "height": 75,
          "width": 75,
          "type": "image",
          "subtype": "photo",
          "caption": "Gov. Chris Christie of New Jersey spoke about the Sept. 11, 2001, attacks at a Republican conference last month.",
          "copyright": "Stephen Crowley/The New York Times"
        }
        (...)
      ]
    }
  ]
}

What I've tried

I tried using JSONutils to automate the struct creation and ended up with this (after deleting the fields I didn't want):

package main

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

type PoliticsJson struct {
	Results []struct {
		Multimedia []struct {
            URL string `json:"url"`
		} `json:"multimedia"`
		Title string `json:"title"`
	} `json:"results"`
}

func retrieveData() []byte {
	url := "http://api.nytimes.com/svc/topstories/v1/politics.json?MYAPIKEY"
	resp, err := http.Get(url)
	if err != nil {
		fmt.Println(err)
	}
	defer resp.Body.Close()
	body, err2 := ioutil.ReadAll(resp.Body)
	if err2 != nil {
		fmt.Println(err2)
	}
	return body
}


func main() {
	var p PoliticsJson

	err := json.Unmarshal(retrieveData(), &p)
	if err != nil {
		panic(err)
	}
	fmt.Println(p.Results[0].Title)
}

I basically just want to print out the title and the URL of the last object in the multimedia array. (I'm just trying to get it to work, so please pardon the error handling.)

Here's the error I get: panic: json: cannot unmarshal string into Go value of type []struct { URL string "json:\"url\"" }

The problem is with the Multimedia struct, apparently. What's confusing me is that this error seems to suggest that it's being interpreted as a string, but I changed the struct to this to make sure:

type PoliticsJson struct {
	Results []struct {
		Multimedia string `json:"multimedia"`
		Title      string `json:"title"`
	} `json:"results"`
}

And I got panic: json: cannot unmarshal array into Go value of type string, which suggests it is being interpreted as an array in the JSON.

Again, I basically just want to print out the title and the URL of the last object in the multimedia array.

答案1

得分: 6

尝试使用您的PoliticsJson和示例Json字符串,成功解析并获取了标题和URL。

我尝试添加了一个多媒体条目,将URL更改为static02,并成功打印了两个URL。

这是相同问题的PlayGround链接:
http://play.golang.org/p/rAJfkD1i7n

编辑

找到了问题所在,这是因为在两个结果中,多媒体是一个字符串,即"multimedia":"",请检查第975行和第1319行。由于期望是一个数组,所以json解析失败,将其转换为"multimedia":[]

英文:

Tried using your PoliticsJson and Sample Json string was able to parse to get Title and URL.

I tried adding one more entry for multi media by changing URL to static02 and able to get both the URL's printed.

Here is the link to PlayGround for the same:
http://play.golang.org/p/rAJfkD1i7n

Edit

Found the issue, it happening because, in 2 of the results multimedia is string i.e. "multimedia":"" check line 975 and 1319. Since array is expected, json is failing because string is found convert this to "multimedia":[].

huangapple
  • 本文由 发表于 2015年12月28日 16:12:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/34489887.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定