在Golang中处理嵌套的JSON结构的最佳方法是什么?

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

What is the best way to work with nested JSON structures in Golang?

问题

我想在Golang中使用JSON,特别是elastic search JSON协议。

JSON是深度嵌套的(这是一个简单的查询):

{
"query": {
"filtered": {
"query": {
"match_all": {}
},
"filter": {
"and": [
{
"range" : {
"b" : {
"from" : 4,
"to" : "8"
}
},
},
{
"term": {
"a": "john"
}
}
]
}
}
}
}

这种结构在Ruby中很容易映射到本地数据结构。

但是在Golang中,似乎你必须使用结构体来定义精确的结构(也许可以从JSON源代码中以编程方式生成它们)。

即使如此,在Golang中处理不同类型对象的数组(例如示例JSON中的"and"键)也需要一些额外的工作和自定义代码。(参考:http://mattyjwilliams.blogspot.co.uk/2013/01/using-go-to-unmarshal-json-lists-with.html)。

在Golang中有更好的处理JSON的方法吗?

英文:

Id like to work with JSON in Golang, in particular the elastic search JSON protocol.

The JSON is deeply nested (this is a simple query):

{
    "query": {
        "filtered": {
            "query": {
                "match_all": {}
            },
            "filter": {
                "and": [
                    {
                        "range" : {
                            "b" : { 
                                "from" : 4, 
                                "to" : "8"
                            }
                        },
                    },
                    {
                        "term": {
                            "a": "john"
                        }
                    }
                ]
            }
        }
    }
}

This structure maps easily to a native data structure in Ruby.

But with Golang, it seems you have to define the exact structure with structs (perhaps generate them programmatically from the JSON source).

Even so, things like arrays of different "types" of objects in JS requires work arounds and custom code. For example the "and" key in the example JSON. (http://mattyjwilliams.blogspot.co.uk/2013/01/using-go-to-unmarshal-json-lists-with.html).

Is there a better way to work with JSON in Golang?

答案1

得分: 5

如果你选择使用结构体的方式,可以考虑以下示例:

{"data": {"children": [
  {"data": {
    "title": "The Go homepage",
    "url": "http://golang.org/"
  }},
  ...
]}}

// -----------

type Item struct {
    Title string
    URL   string
}

type Response struct {
    Data struct {
        Children []struct {
            Data Item
        }
    }
}

来源:http://talks.golang.org/2012/10things.slide#4

英文:

If you choose to go the struct route, consider this example:

{"data": {"children": [
  {"data": {
    "title": "The Go homepage",
    "url": "http://golang.org/"
  }},
  ...
]}}

// -----------

type Item struct {
    Title string
    URL   string
}

type Response struct {
    Data struct {
        Children []struct {
            Data Item
        }
    }
}

Source: http://talks.golang.org/2012/10things.slide#4

答案2

得分: 4

其中一个选项是使用gabs库:https://github.com/Jeffail/gabs

它对于解析和生成复杂的JSON结构非常有用。

以下是从README中生成嵌套JSON的示例:

jsonObj := gabs.New()
// 或者使用gabs.Consume(jsonObject)来处理现有的map[string]interface{}

jsonObj.Set(10, "outter", "inner", "value")
jsonObj.SetP(20, "outter.inner.value2")
jsonObj.Set(30, "outter", "inner2", "value3")

将打印:

{"outter":{"inner":{"value":10,"value2":20},"inner2":{"value3":30}}}
英文:

One of the options is to use gabs library: https://github.com/Jeffail/gabs

It's useful for parsing and generating of the complex json structures.

This is the example of the nested json generation from the README:

jsonObj := gabs.New()
// or gabs.Consume(jsonObject) to work on an existing map[string]interface{}

jsonObj.Set(10, "outter", "inner", "value")
jsonObj.SetP(20, "outter.inner.value2")
jsonObj.Set(30, "outter", "inner2", "value3")

Will print:

{"outter":{"inner":{"value":10,"value2":20},"inner2":{"value3":30}}}

答案3

得分: 1

对于原生的Go语言,可以使用map[string]interface{}或定义一个结构体来处理JSON对象。
如果想要以其他方式轻松访问JSON对象,可以考虑使用JsonPathJason

英文:

For native golang, use map[string]interface{} or define a struct.
For an other way to access json object easily, may be JsonPath or Jason

答案4

得分: 0

根据这篇文章,https://medium.com/@xcoulon/nested-structs-in-golang-2c750403a007,你应该为每个字段定义json标签,然后你就可以使用嵌套结构了。以下是示例代码,你可以将其粘贴到Go Playground中进行测试。

package main

import (
    "encoding/json"
    "fmt"
)

type Config struct {
    Server struct {
        Host string `json:"host"`
        Port string `json:"port"`
    } `json:"server"`
    Postgres struct {
        Host     string `json:"host"`
        User     string `json:"user"`
        Password string `json:"password"`
        DB       string `json:"db"`
    } `json:"database"`
}

func main() {
    jsonConfig := []byte(`{
        "server":{
            "host":"localhost",
            "port":"8080"},
        "database":{
            "host":"localhost",
            "user":"db_user",
            "password":"supersecret",
            "db":"my_db"}}`)
    var config Config
    err := json.Unmarshal(jsonConfig, &config)
    if err != nil {
        panic(err)
    }
    fmt.Printf("Config: %+v\n", config)
}

这段代码定义了一个Config结构体,其中包含了嵌套的ServerPostgres结构体。每个字段都有对应的json标签,以便在进行JSON解析时能够正确地映射字段值。你可以根据需要修改标签的名称和结构体的字段。运行代码后,将输出解析后的配置信息。

英文:

Based on this article, https://medium.com/@xcoulon/nested-structs-in-golang-2c750403a007, you should define json tags for each field, then you are able to use nested struct
The example is below, you can paste it to go playground and test it.

package main

import (
    "encoding/json"
    "fmt"
)
type Config struct {
    Server struct {
        Host string `json:"host"`
        Port string `json:"port"`
        } `json:"server"`
    Postgres struct {
        Host     string `json:"host"`
        User     string `json:"user"`
        Password string `json:"password"`
        DB       string `json:"db"`
    } `json:"database"`
}

func main() {
    jsonConfig := []byte(`{
        "server":{
            "host":"localhost",
            "port":"8080"},
        "database":{
            "host":"localhost",
            "user":"db_user",
            "password":"supersecret",
            "db":"my_db"}}`)
    var config Config
    err := json.Unmarshal(jsonConfig, &config)
    if err != nil {
        panic(err)
    }
    fmt.Printf("Config: %+v\n", config)
}

答案5

得分: 0

如果你愿意的话,使用struct是最好的选择。一个可以帮助的方法是,如果你只使用struct一次,你可以在声明时同时定义它,而不是使用type关键字。另外,你只需要定义你实际使用的字段,其他的可以省略。最后,只要你能够不区分大小写地匹配源字段名,就不需要担心struct标签:

package main
import "encoding/json"

const s = `
{
   "query": {
      "filtered": {
         "query": {"match_all": {}},
         "filter": {
            "and": [
               {"range" : {"b" : {"from": 4, "to": "8"}}},
               {"term": {"a": "john"}}
            ]
         }
      }
   }
}

func main() {
   var m struct {
      Query struct {
         Filtered struct {
            Filter struct { And []struct { Term struct { A string } } }
         }
      }
   }
   json.Unmarshal([]byte(s), &m)
   println(m.Query.Filtered.Filter.And[1].Term.A == "john")
}
英文:

Using a struct is the best option, if you are willing to do it. One item that can help, is if you are only using a struct once, you can just define it at the same time you are declaring it, rather than with a type keyword. Another item, is you only need to define fields that you actually use, others you can omit. Finally, as long as you can case insensitively match the source field names, then you don't need to worry about struct tags:

package main
import "encoding/json"

const s = `
{
   "query": {
      "filtered": {
         "query": {"match_all": {}},
         "filter": {
            "and": [
               {"range" : {"b" : {"from": 4, "to": "8"}}},
               {"term": {"a": "john"}}
            ]
         }
      }
   }
}
`

func main() {
   var m struct {
      Query struct {
         Filtered struct {
            Filter struct { And []struct { Term struct { A string } } }
         }
      }
   }
   json.Unmarshal([]byte(s), &m)
   println(m.Query.Filtered.Filter.And[1].Term.A == "john")
}

huangapple
  • 本文由 发表于 2015年8月4日 06:39:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/31797892.html
匿名

发表评论

匿名网友

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

确定