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

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

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

问题

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

Java伪代码示例:

String json = httpResponse.getBody();
JsonObject object = new JsonObject(json);
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 -->

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

答案1

得分: 33

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

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

这是一个简单的JSON示例:

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

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

package main

import (
	"fmt"
	"encoding/json"
)

func main() {
    // 将下面这行替换为实际获取的响应体
	responseBody := `{"textfield":"我是一段文本。","num":1234,"list":[1,2,3]}`
	var data map[string]interface{}
	err := json.Unmarshal([]byte(responseBody), &data)
	if err != nil {
   		panic(err)
	}
	fmt.Println(data["list"])
	fmt.Println(data["textfield"])
}

希望对你有帮助。

英文:

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 -->

{&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.

package main

import (
	&quot;fmt&quot;
	&quot;encoding/json&quot;
)

func main() {
    // replace this by fetching actual response body
	responseBody := `{&quot;textfield&quot;:&quot;I&#39;m a text.&quot;,&quot;num&quot;:1234,&quot;list&quot;:[1,2,3]}`
	var data map[string]interface{}
	err := json.Unmarshal([]byte(responseBody), &amp;data)
	if err != nil {
   		panic(err)
	}
	fmt.Println(data[&quot;list&quot;])
	fmt.Println(data[&quot;textfield&quot;])
}

Hope this was helpful.

答案2

得分: 5

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

package main

import (
  "encoding/json"
  "fmt"
)

type Person struct {
  FirstName string `json:"first_name"`
  LastName  string `json:"last_name"`
}

func main() {
  jsonString := []byte(`{"first_name": "John", "last_name": "Doe", "middle_name": "Anderson"}`)

  var person Person
  if err := json.Unmarshal(jsonString, &person); err != nil {
    panic(err)
  }

  fmt.Println(person)
}

以上代码演示了如何使用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:

package main

import (
  &quot;encoding/json&quot;
  &quot;fmt&quot;
)
  
type Person struct {
  FirstName string `json:&quot;first_name&quot;`
  LastName  string `json:&quot;last_name&quot;`
}
  
func main() {
  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;)

  var person Person
  if err := json.Unmarshal(jsonString, &amp;person); err != nil {
    panic(err)
  }
  
  fmt.Println(person)
}

答案3

得分: 3

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

package main

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

func main() {
   r, e := http.Get("https://github.com/manifest.json")
   if e != nil {
      panic(e)
   }
   body := map[string]interface{}{}
   json.NewDecoder(r.Body).Decode(&body)
   /*
   [map[
      id:com.github.android
      platform:play
      url:https://play.google.com/store/apps/details?id=com.github.android
   ]]
   */
   fmt.Println(body["related_applications"])
}

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

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

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

/*
map[
   id:com.github.android
   platform:play
   url:https://play.google.com/store/apps/details?id=com.github.android
]
*/
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:

package main

import (
   &quot;encoding/json&quot;
   &quot;fmt&quot;
   &quot;net/http&quot;
)

func main() {
   r, e := http.Get(&quot;https://github.com/manifest.json&quot;)
   if e != nil {
      panic(e)
   }
   body := map[string]interface{}{}
   json.NewDecoder(r.Body).Decode(&amp;body)
   /*
   [map[
      id:com.github.android
      platform:play
      url:https://play.google.com/store/apps/details?id=com.github.android
   ]]
   */
   fmt.Println(body[&quot;related_applications&quot;])
}

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

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

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

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

答案4

得分: 1

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

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

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

英文:

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

body, err := ioutil.ReadAll(resp.Body)
map := &amp;map[string]interface{}{}
json.Unmarshal(body, map)
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:

确定