Unmarshal JSON into a map in Go

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

Unmarshal JSON into a map in Go

问题

我遇到了一些困难,无法弄清楚如何将 JSON 文件的“子部分”加载到地图元素中。背景:我正在尝试解组一个相当复杂的配置文件,它具有严格的结构,因此我认为最好解组为“静态”结构,而不是解组为 interface{}。

这是一个简单的 JSON 文件示例:

{
"set1": {
"a":"11",
"b":"22",
"c":"33"
}
}

这段代码是可以工作的:

package main

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

type JSONType struct {
FirstSet ValsType json:"set1"
}

type ValsType struct {
A string json:"a"
B string json:"b"
C string json:"c"
}

func main() {
file, e := ioutil.ReadFile("./test1.json")
if e != nil {
fmt.Println("file error")
os.Exit(1)
}
var s JSONType
json.Unmarshal([]byte(file), &s)
fmt.Printf("\nJSON: %+v\n", s)
}

但是这段代码不行:

package main

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

type JSONType struct {
FirstSet ValsType json:"set1"
}

type ValsType struct {
Vals map[string]string
}

func main() {
file, e := ioutil.ReadFile("./test1.json")
if e != nil {
fmt.Println("file error")
os.Exit(1)
}

var s JSONType
s.FirstSet.Vals = map[string]string{}
json.Unmarshal([]byte(file), &s)
fmt.Printf("\nJSON: %+v\n", s)

}

Vals 地图没有加载。我做错了什么?谢谢帮助!

这是一个更好的示例:

{
"set1": {
"a": {
"x": "11",
"y": "22",
"z": "33"
},
"b": {
"x": "211",
"y": "222",
"z": "233"
},
"c": {
"x": "311",
"y": "322",
"z": "333"
}
}
}

代码:

package main

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

type JSONType struct {
FirstSet map[string]ValsType json:"set1"
}

type ValsType struct {
X string json:"x"
Y string json:"y"
Z string json:"z"
}

func main() {
file, e := ioutil.ReadFile("./test1.json")
if e != nil {
fmt.Println("file error")
os.Exit(1)
}
var s JSONType
json.Unmarshal([]byte(file), &s)
fmt.Printf("\nJSON: %+v\n", s)
}

英文:

I'm having trouble figuring out how to load a "subsection" of JSON file into a map element. Background: I'm trying to unmarshal a somewhat complicated configuration file which has a strict structure, so I assume it's preferable to unmarshal into a "static" structure rather than into an interface{}.

Here's a simple JSON file for example:

{
    "set1": {
        "a":"11",
        "b":"22",
        "c":"33"
    }
}

This code works:

package main

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

type JSONType struct {
    FirstSet ValsType `json:"set1"`
}

type ValsType struct {
    A string `json:"a"`
    B string `json:"b"`
    C string `json:"c"`
}

func main() {
    file, e := ioutil.ReadFile("./test1.json")
    if e != nil {
        fmt.Println("file error")
        os.Exit(1)
    }
    var s JSONType
    json.Unmarshal([]byte(file), &s)
    fmt.Printf("\nJSON: %+v\n", s)
}

But this doesn't:

package main

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

type JSONType struct {
    FirstSet ValsType `json:"set1"`
}

type ValsType struct {
    Vals map[string]string
}

func main() {
    file, e := ioutil.ReadFile("./test1.json")
    if e != nil {
        fmt.Println("file error")
        os.Exit(1)
    }

    var s JSONType
    s.FirstSet.Vals = map[string]string{}
    json.Unmarshal([]byte(file), &s)
    fmt.Printf("\nJSON: %+v\n", s)
}

The Vals map isn't loaded. What am I doing wrong? Thanks for any help!

Here's a better example:

{
    "set1": {
        "a": {
            "x": "11",
            "y": "22",
            "z": "33"
        },
        "b": {
            "x": "211",
            "y": "222",
            "z": "233"
        },
        "c": {
            "x": "311",
            "y": "322",
            "z": "333"
        },
    }
}

Code:

package main

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

type JSONType struct {
    FirstSet map[string]ValsType `json:"set1"`
}

type ValsType struct {
    X string `json:"x"`
    Y string `json:"y"`
    Z string `json:"z"`
}

func main() {
    file, e := ioutil.ReadFile("./test1.json")
    if e != nil {
        fmt.Println("file error")
        os.Exit(1)
    }
    var s JSONType
    json.Unmarshal([]byte(file), &s)
    fmt.Printf("\nJSON: %+v\n", s)
}

答案1

得分: 4

我相信这是因为你的模型中有额外的间接层。

type JSONType struct {
    FirstSet map[string]string `json:"set1"`
}

应该就足够了。如果你指定了map[string]string,那么JSON中的对象将被识别为该映射。你创建了一个结构体来包装它,但是像这样的JSON块:

{
    "a":"11",
    "b":"22",
    "c":"33"
}

实际上可以直接解组为map[string]string

编辑:根据评论中的其他模型

type JSONType struct {
    FirstSet map[string]Point `json:"set1"`
}

type Point struct {
     X string `json:"x"`
     Y string `json:"y"`
     Z string `json:"z"`
}

这样可以将你的三维点作为静态类型的结构体。如果你想快速而简单地做,你也可以使用map[string]map[string]string,这将给出一个映射的映射,这样你就可以像FirstSet["a"]["x"]这样访问点的值,它将返回"11"

第二次编辑;显然我没有仔细阅读你的代码,因为上面的例子是相同的。基于此,我猜你想要的是

FirstSet map[string]map[string]string `json:"set1"`

选项。尽管在你的编辑后对我来说并不完全清楚。

英文:

I believe that is because you have extra layer of indirection in your models.

type JSONType struct {
    FirstSet map[string]string `json:"set1"`
}

Should suffice. if you specify map[string]string the object in json is recognized as that map. You created a struct to wrap it but a blob of json like this;

{
    "a":"11",
    "b":"22",
    "c":"33"
}

Actually can unmarshal directly into map[string]string

EDIT: Some other models based on the comment

type JSONType struct {
    FirstSet map[string]Point `json:"set1"`
}

type Point struct {
     X string `json:"x"`
     Y string `json:"y"`
     Z string `json:"z"`
}

This makes your 3-d point a statically typed struct which is fine. If you wanted to do the quick and dirty you could also just use map[string]map[string]string
which would give a map of maps so you could access the point values like FirstSet["a"]["x"] and it would return "11".

Second edit; clearly I didn't read you code that closely since the above example is the same. Based on that I would guess you want the

 FirstSet map[string]map[string]string `json:"set1"`

option. Though it's not entirely clear to me after your edit.

huangapple
  • 本文由 发表于 2015年6月17日 01:29:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/30874299.html
匿名

发表评论

匿名网友

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

确定