使用多层嵌套映射解组JSON

时间:2016-09-29 04:21:46

标签: json go

我意识到这个问题与stackoverflow上的其他问题非常相似,但我无法将其他问题建模到我的用例。

我的JSON看起来像这样(本文简化)

{
  "somekey": "string",
  "state": {
    "groups": {
      "host:host1": {
        "status": "OK",
        "morethings": "blah"
      },
      "host:host2": {
        "status": "Alert",
        "morethings": "blah"
      }
    }
  }
}

我正在尝试将groups下的哈希值放入数组中,以便我可以迭代并检查主机的状态。
根据这里的其他一些帖子,我觉得我在example

的正确轨道上
package main

import (
    "encoding/json"
    "fmt"
)

const jsonStream = `
{
  "state": {
    "groups": {
      "host:i-b3a6cea5": {
        "status": "OK",
        "last_triggered_ts": null,
        "last_nodata_ts": null,
        "name": "host:i-b3a6cea5",
        "last_notified_ts": null,
        "last_resolved_ts": null
      },
      "host:i-4d81ca7c": {
        "status": "OK",
        "last_triggered_ts": null,
        "last_nodata_ts": null,
        "name": "host:i-4d81ca7c",
        "last_notified_ts": null,
        "last_resolved_ts": null
      },
      "host:i-a03a7758": {
        "status": "Alert",
        "triggering_value": {
          "to_ts": 1475092440,
          "value": 2,
          "from_ts": 1475092380
        },
        "last_triggered_ts": 1475092440,
        "last_nodata_ts": null,
        "name": "host:i-a03a7758",
        "last_notified_ts": 1475092440,
        "last_resolved_ts": null
      }
    }
  }
}`

type hostDetails struct {
    Status string `json:"status"`
    Name   string `json:"name"`
}

type GroupsData struct {
    Groups map[string]hostDetails `json:"groups"`
}

type Data struct {
    State map[string]GroupsData `json:"state"`
}

func main() {
    var data Data

    err := json.Unmarshal([]byte(jsonStream), &data)
    if err != nil {
        fmt.Println(err)
    }

    fmt.Println(data)

}

但我最终只得到一个空的数据结构:

{map[groups:{map[]}]}

要查看我是否在正确的轨道上,我修改了我的JSON并取出了state键,以便groups位于顶层。
当我这样做时,它会填充数据结构,如here

所示

我很难理解为什么我可以处理1级嵌套而不是第二级呢? 我的穴居人大脑认为我应该能够重复使用这种模式,以获得尽可能多的嵌套水平 在这一点上,我一直在摆弄大部分时间,觉得我错过了一些摆在我面前的东西,却看不到它。
关于如何处理额外的嵌套层,任何指针都会受到赞赏。

2 个答案:

答案 0 :(得分:0)

1 - 您可以使用以下方法删除一个额外级别:

var data map[string]GroupsData

The Go Playground上试用:

package main

import (
    "encoding/json"
    "fmt"
)

func main() {
    var data map[string]GroupsData
    err := json.Unmarshal([]byte(jsonStream), &data)
    if err != nil {
        fmt.Println(err)
    }    
    fmt.Println(data)    
}

type GroupsData struct {
    Groups map[string]HostDetails `json:"groups"`
}

type HostDetails struct {
    Status string `json:"status"`
    Name   string `json:"name"`
}

const jsonStream = `
{
    "state": {
        "groups": {
            "host:i-b3a6cea5": {
                "status": "OK",
                "last_triggered_ts": null,
                "last_nodata_ts": null,
                "name": "host:i-b3a6cea5",
                "last_notified_ts": null,
                "last_resolved_ts": null
            },
            "host:i-4d81ca7c": {
                "status": "OK",
                "last_triggered_ts": null,
                "last_nodata_ts": null,
                "name": "host:i-4d81ca7c",
                "last_notified_ts": null,
                "last_resolved_ts": null
            },
            "host:i-a03a7758": {
                "status": "Alert",
                "triggering_value": {
                    "to_ts": 1475092440,
                    "value": 2,
                    "from_ts": 1475092380
                },
                "last_triggered_ts": 1475092440,
                "last_nodata_ts": null,
                "name": "host:i-a03a7758",
                "last_notified_ts": 1475092440,
                "last_resolved_ts": null
            }
        }
    }
}`

输出:

map[state:{map[host:i-b3a6cea5:{OK host:i-b3a6cea5} host:i-4d81ca7c:{OK host:i-4d81ca7c} host:i-a03a7758:{Alert host:i-a03a7758}]}]

2 - 您可以使用:

type Data struct {
    State GroupsData `json:"state"`
}   

The Go Playground上试用:

package main

import (
    "encoding/json"
    "fmt"
)

func main() {
    var data Data    
    err := json.Unmarshal([]byte(jsonStream), &data)
    if err != nil {
        fmt.Println(err)
    }    
    fmt.Println(data)    
}

type Data struct {
    State GroupsData `json:"state"`
}
type GroupsData struct {
    Groups map[string]hostDetails `json:"groups"`
}

type hostDetails struct {
    Status string `json:"status"`
    Name   string `json:"name"`
}

const jsonStream = `
{
  "state": {
    "groups": {
      "host:i-b3a6cea5": {
        "status": "OK",
        "last_triggered_ts": null,
        "last_nodata_ts": null,
        "name": "host:i-b3a6cea5",
        "last_notified_ts": null,
        "last_resolved_ts": null
      },
      "host:i-4d81ca7c": {
        "status": "OK",
        "last_triggered_ts": null,
        "last_nodata_ts": null,
        "name": "host:i-4d81ca7c",
        "last_notified_ts": null,
        "last_resolved_ts": null
      },
      "host:i-a03a7758": {
        "status": "Alert",
        "triggering_value": {
          "to_ts": 1475092440,
          "value": 2,
          "from_ts": 1475092380
        },
        "last_triggered_ts": 1475092440,
        "last_nodata_ts": null,
        "name": "host:i-a03a7758",
        "last_notified_ts": 1475092440,
        "last_resolved_ts": null
      }
    }
  }
}`

输出:

{{map[host:i-b3a6cea5:{OK host:i-b3a6cea5} host:i-4d81ca7c:{OK host:i-4d81ca7c} host:i-a03a7758:{Alert host:i-a03a7758}]}}

您的code在JSON数据中使用了一个额外级别"state": {}The Go Playground

答案 1 :(得分:0)

你的错误是Data.State不应该是地图。如果将定义更改为

type Data struct {
    State GroupsData `json:"state"`
}

它有效:https://play.golang.org/p/oRjSJMDzU8