How do I read one value from a JSON file using Go

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

How do I read one value from a JSON file using Go

问题

我是你的中文翻译助手,以下是翻译好的内容:

我刚开始学习使用Go编程,如果这是一些显而易见的东西,我表示抱歉。我有一个名为foo.jsonJSON文件:

{"type":"fruit","name":"apple","color":"red"}

我正在编写一个Go程序,当JSON文件中的"name"值为"apple"时,需要执行某些操作。它不需要从该JSON文件中获取其他信息,因为该文件在代码的另一个区域用于完全不同的目的。

我已经阅读了有关Decode()和Unmarshal()的文档,以及大约30个不同的网页,描述了如何将整个文件读入结构体等等。但对于我想要做的事情来说,这似乎都过于复杂了,我只想编写正确的代码来实现这个伪代码的前两行:

file, _ := os.Open("foo.json")
name = file["name"]
if (name == "apple") {
    do stuff
}

这样,我将得到一个名为"name"的Go变量,其中包含字符串值"apple"。在Go中,应该如何正确实现这个功能呢?

英文:

I an new to programming in Go so apologies if this is something obvious. I have a JSON file named foo.json:

{"type":"fruit","name":"apple","color":"red"}

and I am writing a Go program that has to do something when the "name" value in the JSON file is "apple". It needs no other information from that JSON file as that file is used for a completely different purpose in another area of the code.

I have read documentation on Decode() and Unmarshal() and abut 30 different web pages describing how to read the whole file into structures, etc. but it all seems extremely complicated for what I want to do which is just write the correct code to implement the first 2 lines of this pseudo-code:

file, _ := os.Open("foo.json")
name = file["name"]
if (name == "apple") {
    do stuff
}

such that I end up with a Go variable named name that contains the string value apple. What is the right way to do this in Go?

答案1

得分: 4

一件事是读取文件,另一件事是解码JSON文档。我给你提供一个完整的例子,可以同时完成这两个任务。要运行它,你需要在代码或可执行文件的同一目录下有一个名为 file.json 的文件:

package main

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"os"
)

func main() {
	f, err := os.Open("file.json") // file.json 包含了 JSON 内容
	if err != nil {
		log.Fatal(err)
	}

	bb, err := ioutil.ReadAll(f)
	if err != nil {
		log.Fatal(err)
	}

	doc := make(map[string]interface{})
	if err := json.Unmarshal(bb, &doc); err != nil {
		log.Fatal(err)
	}

	if name, contains := doc["name"]; contains {
		log.Printf("Happy end we have a name: %q\n", name)
	} else {
		log.Println("Json document doesn't have a name field.")
	}

	log.Printf("full json: %s", string(bb))
}

https://play.golang.org/p/0u04MwwGfn

英文:

One thing is reading a file and other one is decoding a JSON document. I leave you a full example doing both. To run it you have to have a file called file.json in the same directory of your code or binary executable:

package main

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"os"
)

func main() {
	f, err := os.Open("file.json") // file.json has the json content
	if err != nil {
		log.Fatal(err)
	}

	bb, err := ioutil.ReadAll(f)
	if err != nil {
		log.Fatal(err)
	}

	doc := make(map[string]interface{})
	if err := json.Unmarshal(bb, &doc); err != nil {
		log.Fatal(err)
	}

	if name, contains := doc["name"]; contains {
		log.Printf("Happy end we have a name: %q\n", name)
	} else {
		log.Println("Json document doesn't have a name field.")
	}

	log.Printf("full json: %s", string(bb))
}

https://play.golang.org/p/0u04MwwGfn

答案2

得分: 4

你想要的最简单的方法是将其解码为一个结构体。

假设格式与{"type":"fruit","name":"apple","color":"red"}类似:

type Name struct {
    Name string `json:"name"`
}

var data []byte
data, _ = ioutil.ReadFile("foo.json")

var str Name
_ = json.Unmarshal(data, &str)

if str.Name == "apple" {
    // 做一些操作
}

你还可以使用第三方库,比如gabsjason

Gabs:

jsonParsed, err := gabs.ParseJSON(data)
name, ok := jsonParsed.Path("name").Data().(string)

Jason:

v, _ := jason.NewObjectFromBytes(data)
name, _ := v.GetString("name")

更新:

结构体

type Name struct {
    Name string `json:"name"`
}

{"name":"foo"}的JSON等效形式。

因此,对于具有不同格式的以下JSON,解组将不起作用。

[{"name":"foo"}]

{"bar":{"name":"foo"}}

PS:正如W.K.S所提到的,在你的情况下,使用一个匿名结构体就足够了,因为你不会在其他地方使用这个结构体。

英文:

The easiest method to do what you want is to decode into a struct.

Provided the format remains similar to {"type":"fruit","name":"apple","color":"red"}

type Name struct {
	Name string `json:"name"`
}

var data []byte
data, _ = ioutil.ReadFile("foo.json")
	
var str Name
_ = json.Unmarshal(data, &str)
	
if str.Name == "apple" {
	// Do Stuff
}

Your other option is to use third party libraries such as gabs or jason.

Gabs :

jsonParsed, err := gabs.ParseJSON(data)
name, ok := jsonParsed.Path("name").Data().(string)

Jason :

v, _ := jason.NewObjectFromBytes(data)
name, _ := v.GetString("name")

Update :

The structure

type Name struct {
    Name string `json:"name"`
}

is the json equivalent of {"name":"foo"}.

So unmarshaling won't work for the following json with different formats.

[{"name":"foo"}]

{"bar":{"name":"foo"}}

PS : As mentioned by W.K.S. In your case an anonymous struct would suffice since you're not using this structure for anything else.

答案3

得分: 1

我也尝试过在PHP中找到一个简单的解决方案,比如$d = json_decode($json, true),并得出结论在Golang中没有这样简单的方法。以下是我能做出的最简单的解决方案(为了清晰起见,省略了检查步骤):

var f interface{}
err = json.Unmarshal(file, &f)

m := f.(map[string]interface{})
if m["name"] == "apple" {
  // 做一些操作
}

其中:

  • file 是一个包含 JSON 字符串的字节数组,
  • f 接口用作未知 JSON 结构的通用容器,
  • m 是由 类型断言 返回的映射。

我们可以断言 f 是一个字符串映射,因为 Unmarshal() 会为任何 JSON 输入构建该类型的变量。至少,我无法让它返回其他类型。可以通过 运行时反射 来检测变量的类型:

fmt.Printf("f 的类型 = %s\n", reflect.TypeOf(f))

对于上面的 f 变量,该代码将打印 f 的类型 = map[string]interface {}

示例

以下是带有必要检查的完整代码:

package main

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

func main() {
  // 将整个文件读入字节数组
  file, err := ioutil.ReadFile("foo.json")
  if err != nil {
    fmt.Fprintf(os.Stderr, "读取文件失败:%s\n", err)
    os.Exit(1)
  }

  var f interface{}
  err = json.Unmarshal(file, &f)
  if err != nil {
    fmt.Fprintf(os.Stderr, "解析 JSON 失败:%s\n", err)
    os.Exit(1)
  }

  // 通过类型断言将 `f` 强制转换为映射。
  m := f.(map[string]interface{})
  fmt.Printf("解析的数据:%v\n", m)

  // 现在我们可以检查解析的数据是否包含 'name' 键
  if m["name"] == "apple" {
    fmt.Print("找到了苹果\n")
  }
}

输出

解析的数据:map[type:fruit name:apple color:red]
找到了苹果
英文:

I have also tried to find a simple solution such as $d = json_decode($json, true) in PHP and came to the conclusion that there is no such simple way in Golang. The following is the simplest solution I could make (the checks are skipped for clarity):

var f interface{}
err = json.Unmarshal(file, &f)

m := f.(map[string]interface{})
if (m["name"] == "apple") {
  // Do something
}

where

  • file is an array of bytes of JSON string,
  • f interface serves as a generic container for unknown JSON structure,
  • m is a map returned by the type assertion.

We can assert that f is a map of strings, because Unmarshal() builds a variable of that type for any JSON input. At least, I couldn't make it return something different. It is possible to detect the type of a variable by means of run-time reflection:

fmt.Printf("Type of f = %s\n", reflect.TypeOf(f))

For the f variable above, the code will print Type of f = map[string]interface {}.

Example

And this is the full code with necessary checks:

package main

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

func main() {
  // Read entire file into an array of bytes
  file, err := ioutil.ReadFile("foo.json")
  if (err != nil) {
    fmt.Fprintf(os.Stderr, "Failed read file: %s\n", err)
    os.Exit(1)
  }

  var f interface{}
  err = json.Unmarshal(file, &f)
  if (err != nil) {
    fmt.Fprintf(os.Stderr, "Failed to parse JSON: %s\n", err)
    os.Exit(1)
  }

  // Type-cast `f` to a map by means of type assertion.
  m := f.(map[string]interface{})
  fmt.Printf("Parsed data: %v\n", m)

  // Now we can check if the parsed data contains 'name' key
  if (m["name"] == "apple") {
    fmt.Print("Apple found\n")
  }
}

Output

Parsed data: map[type:fruit name:apple color:red]
Apple found

答案4

得分: 1

这样做的正确方式是将其解码为一个只包含所需字段的匿名结构体实例。

func main() {
    myStruct := struct{ Name string }{}
    json.Unmarshal([]byte(`{"type":"fruit","name":"apple","color":"red"}`), &myStruct)
    fmt.Print(myStruct.Name)
}

Playground链接

另外,你也可以使用 Jeffails/gabs JSON解析器:

jsonParsed, _ := gabs.ParseJSON([]byte(`{"type":"fruit","name":"apple","color":"red"}`))
value, ok := jsonParsed.Path("name").Data().(string)
英文:

The proper Go way of doing this would be to decode into an instance of an anonymous struct containing only the field you need.

func main() {
	myStruct := struct{ Name string }{}
	json.Unmarshal([]byte(`{"type":"fruit","name":"apple","color":"red"}`), &myStruct)
	fmt.Print(myStruct.Name)
}

Playground Link

Alternatively, You could use Jeffails/gabs JSON Parser:

jsonParsed,_ := gabs.ParseJSON([]byte(`{"type":"fruit","name":"apple","color":"red"}`));
value, ok = jsonParsed.Path("name").Data().(string)

huangapple
  • 本文由 发表于 2016年12月23日 11:04:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/41294649.html
匿名

发表评论

匿名网友

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

确定