有没有一种方法可以在不构建结构体的情况下从HTTP响应中提取JSON数据?

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

Is there a way to extract JSON from an http response without having to build structs?

问题

我看到的所有方法都涉及构建结构体并将数据解组到结构体中。但是,如果我收到的是具有数百个字段的JSON响应呢?我不想为了获取所需数据而创建100个字段的结构体。从Java背景来看,有简单的方法可以将HTTP响应直接作为字符串获取,然后将JSON字符串传递给允许轻松遍历的JSON对象。这非常简单。在Go语言中有类似的方法吗?

Java伪代码示例:

  1. String json = httpResponse.getBody();
  2. JsonObject object = new JsonObject(json);
  3. object.get("desiredKey");
英文:

All of the ways I'm seeing involve building structs and unmarshalling the data into the struct. But what if I'm getting JSON responses with hundreds of fields? I don't want to have to create 100 field structs just to be able to get to the data I want. Coming from a Java background there are easy ways to simply get the http response as a string and then pass the JSON string into a JSON object that allows for easy traversal. It's very painless. Is there anything like this in Go?

Java example in pseudo code:

<!--code: java -->

  1. String json = httpResponse.getBody();
  2. JsonObject object = new JsonObject(json);
  3. object.get(&quot;desiredKey&quot;);

答案1

得分: 33

Golang:在不使用结构体作为辅助工具的情况下从HTTP响应中获取JSON

这是我们经常遇到的典型场景。可以通过json.Unmarshal来实现。

这是一个简单的JSON示例:

  1. {"textfield":"我是一段文本。","num":1234,"list":[1,2,3]}

它被序列化后通过网络发送,并在Golang端进行反序列化。

  1. package main
  2. import (
  3. "fmt"
  4. "encoding/json"
  5. )
  6. func main() {
  7. // 将下面这行替换为实际获取的响应体
  8. responseBody := `{"textfield":"我是一段文本。","num":1234,"list":[1,2,3]}`
  9. var data map[string]interface{}
  10. err := json.Unmarshal([]byte(responseBody), &data)
  11. if err != nil {
  12. panic(err)
  13. }
  14. fmt.Println(data["list"])
  15. fmt.Println(data["textfield"])
  16. }

希望对你有帮助。

英文:

Golang: fetch JSON from an HTTP response without using structs as helpers

This is a typical scenario we come across. This is achieved by json.Unmarshal.

Here is a simple json

<!-- language: javascript -->

  1. {&quot;textfield&quot;:&quot;I&#39;m a text.&quot;,&quot;num&quot;:1234,&quot;list&quot;:[1,2,3]}

which is serialized to send across the network and unmarshaled at Golang end.

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;encoding/json&quot;
  5. )
  6. func main() {
  7. // replace this by fetching actual response body
  8. responseBody := `{&quot;textfield&quot;:&quot;I&#39;m a text.&quot;,&quot;num&quot;:1234,&quot;list&quot;:[1,2,3]}`
  9. var data map[string]interface{}
  10. err := json.Unmarshal([]byte(responseBody), &amp;data)
  11. if err != nil {
  12. panic(err)
  13. }
  14. fmt.Println(data[&quot;list&quot;])
  15. fmt.Println(data[&quot;textfield&quot;])
  16. }

Hope this was helpful.

答案2

得分: 5

json.Unmarshal方法将解组为一个结构体,该结构体不包含原始JSON对象中的所有字段。换句话说,你可以挑选你需要的字段。以下是一个示例,其中FirstName和LastName是挑选的字段,而MiddleName被忽略了:

  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. )
  6. type Person struct {
  7. FirstName string `json:"first_name"`
  8. LastName string `json:"last_name"`
  9. }
  10. func main() {
  11. jsonString := []byte(`{"first_name": "John", "last_name": "Doe", "middle_name": "Anderson"}`)
  12. var person Person
  13. if err := json.Unmarshal(jsonString, &person); err != nil {
  14. panic(err)
  15. }
  16. fmt.Println(person)
  17. }

以上代码演示了如何使用json.Unmarshal方法将JSON字符串解组到Person结构体中,并只选择FirstName和LastName字段。

英文:

The json.Unmarshal method will unmarshal to a struct that does not contain all the fields in the original JSON object. In other words, you can cherry-pick your fields. Here is an example where FirstName and LastName are cherry-picked and MiddleName is ignored from the json string:

  1. package main
  2. import (
  3. &quot;encoding/json&quot;
  4. &quot;fmt&quot;
  5. )
  6. type Person struct {
  7. FirstName string `json:&quot;first_name&quot;`
  8. LastName string `json:&quot;last_name&quot;`
  9. }
  10. func main() {
  11. jsonString := []byte(&quot;{\&quot;first_name\&quot;: \&quot;John\&quot;, \&quot;last_name\&quot;: \&quot;Doe\&quot;, \&quot;middle_name\&quot;: \&quot;Anderson\&quot;}&quot;)
  12. var person Person
  13. if err := json.Unmarshal(jsonString, &amp;person); err != nil {
  14. panic(err)
  15. }
  16. fmt.Println(person)
  17. }

答案3

得分: 3

这里的其他答案是误导性的,因为它们没有展示如果你尝试在Map中深入一层会发生什么。这个示例足够好地工作:

  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "net/http"
  6. )
  7. func main() {
  8. r, e := http.Get("https://github.com/manifest.json")
  9. if e != nil {
  10. panic(e)
  11. }
  12. body := map[string]interface{}{}
  13. json.NewDecoder(r.Body).Decode(&body)
  14. /*
  15. [map[
  16. id:com.github.android
  17. platform:play
  18. url:https://play.google.com/store/apps/details?id=com.github.android
  19. ]]
  20. */
  21. fmt.Println(body["related_applications"])
  22. }

但是,如果你尝试深入一层,它会失败:

  1. /*
  2. invalid operation: body["related_applications"][0] (type interface {} does not
  3. support indexing)
  4. */
  5. fmt.Println(body["related_applications"][0])

相反,你需要在每个深度级别上进行类型断言:

  1. /*
  2. map[
  3. id:com.github.android
  4. platform:play
  5. url:https://play.google.com/store/apps/details?id=com.github.android
  6. ]
  7. */
  8. fmt.Println(body["related_applications"].([]interface{})[0])
英文:

The other answers here are misleading, as they don't show you what happens if you try to go deeper in the Map. This example works fine enough:

  1. package main
  2. import (
  3. &quot;encoding/json&quot;
  4. &quot;fmt&quot;
  5. &quot;net/http&quot;
  6. )
  7. func main() {
  8. r, e := http.Get(&quot;https://github.com/manifest.json&quot;)
  9. if e != nil {
  10. panic(e)
  11. }
  12. body := map[string]interface{}{}
  13. json.NewDecoder(r.Body).Decode(&amp;body)
  14. /*
  15. [map[
  16. id:com.github.android
  17. platform:play
  18. url:https://play.google.com/store/apps/details?id=com.github.android
  19. ]]
  20. */
  21. fmt.Println(body[&quot;related_applications&quot;])
  22. }

but if you try to go one level deeper, it fails:

  1. /*
  2. invalid operation: body[&quot;related_applications&quot;][0] (type interface {} does not
  3. support indexing)
  4. */
  5. fmt.Println(body[&quot;related_applications&quot;][0])

Instead, you would need to assert type at each level of depth:

  1. /*
  2. map[
  3. id:com.github.android
  4. platform:play
  5. url:https://play.google.com/store/apps/details?id=com.github.android
  6. ]
  7. */
  8. fmt.Println(body[&quot;related_applications&quot;].([]interface{})[0])

答案4

得分: 1

你可以将其解组为一个map[string]interface{}类型。

  1. body, err := ioutil.ReadAll(resp.Body)
  2. map := &map[string]interface{}{}
  3. json.Unmarshal(body, map)
  4. desiredValue := (*map)["desiredKey"]

接收到的JSON必须具有对象作为最外层元素。该map还可以包含列表或嵌套的map,具体取决于JSON的结构。

英文:

You can as well unmarshal it into a map[string]interface{}

  1. body, err := ioutil.ReadAll(resp.Body)
  2. map := &amp;map[string]interface{}{}
  3. json.Unmarshal(body, map)
  4. desiredValue := map[&quot;desiredKey&quot;]

The received json must have an object as the most outer element. The map can also contain lists or nested maps, depending on the json.

huangapple
  • 本文由 发表于 2017年1月24日 05:24:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/41815909.html
匿名

发表评论

匿名网友

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

确定