dtjw6660 2016-10-03 22:44
浏览 49
已采纳

在Go中解析JSON

My question is about parsing JSON files in golang.

Specifically, I am trying to parse output of a command "docker network inspect bridge", which happens to be in JSON format. The command is described here. My goal is to get a list of "IPv4Address" for the listed containers.

I have tried to do this but failing to convert map[string]interface{} to map[string]string. My code is here:- https://play.golang.org/p/eO_j996gGb

$ sudo docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "b2b1a2cba717161d984383fd68218cf70bbbd17d328496885f7c921333228b0f",
        "Scope": "local",
        "Driver": "bridge",
        "IPAM": {
            "Driver": "default",
            "Config": [
                {
                    "Subnet": "172.17.42.1/16",
                    "Gateway": "172.17.42.1"
                }
            ]
        },
        "Internal": false,
        "Containers": {
            "bda12f8922785d1f160be70736f26c1e331ab8aaf8ed8d56728508f2e2fd4727": {
                "Name": "container2",
                "EndpointID": "0aebb8fcd2b282abe1365979536f21ee4ceaf3ed56177c628eae9f706e00e019",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            },
            "f2870c98fd504370fb86e59f32cd0753b1ac9b69b7d80566ffc7192a82b3ed27": {
                "Name": "container1",
                "EndpointID": "a00676d9c91a96bbe5bcfb34f705387a33d7cc365bac1a29e4e9728df92d10ad",
                "MacAddress": "02:42:ac:11:00:01",
                "IPv4Address": "172.17.0.1/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        }
    }
]

What is the correct way to parse such JSON files in golang. I did try using type conversion but doesn't help. I have tried many things but finally could only get as far as the code shown in the snippet. How can I extract the IPv4Address field from the "cont" object?

Link to go playground snippet I have is https://play.golang.org/p/eO_j996gGb. Any help is greatly appreciated (willing to try things out, don't need just the code but ideas :) Thanks.

  • 写回答

1条回答 默认 最新

  • douding6266 2016-10-03 22:51
    关注

    Your code just needs to be modified to further unpackage the data. You're leaving it with each container object represented as an interface{} which makes it so you can't access the fields within it. Another assert on each to make it a map[string]interface{} will allow you to access the fields within by name (like IPv4Address). Here's a working example; https://play.golang.org/p/4OC5axN4Gd

    Here's the important code change;

        containers := (foo[0]["Containers"]).(map[string]interface{})
    
        //fmt.Printf("containers %+v", containers)
        for _, v := range containers {
            unwrapped := v.(map[string]interface{})
            fmt.Printf("
    cont %+v
    ", unwrapped["IPv4Address"])            
        }
    

    v is just an interface{} so you have no way of accessing the IPv4Address field without asserting again/converting into a type.

    Now that works fine, however, I would recommend getting away from the heavy use of interfaces in your code. Your code is full of unsafe operations that create a need for a lot of error handling (like every time you attempt access into the map you have the potential to throw, as well as anytime you do a type assert). There are plenty of examples of how to do this here on SO but if you leave a comment requesting it I can produce another example that will unmarshal into structs. This is a lot more safe and maintainable imo because most errors will be raised on the call to unmarshal, rather than having potentially a lot of code that works with the results that could all cause a panic.

    Here is some play code that has all the types in it and uses unmarshal; https://play.golang.org/p/VfHst9GaiR

    Your types can be represented with the following;

    type DockerInstance struct {
        Name string `json:"Name"`
        Id string `json:"Id"`
        Scope string `json:"Scope"`
        Driver string `json:"Driver"`   
        EnableIPv6 bool `json:"EnableIPv6"`
        IPAM IPAM `json:"IPAM"`
        Internal bool `json:"Internal"`
        Containers map[string]Container `json:"Containers"`
        Options map[string]string `json:"Options"`
        Labels interface{} `json:"Labels"`
    }
    
    type IPAM struct {
        Driver string `json:"Driver"`
        Options interface{} `json:"Options"`
        Config []Conf `json:"Config"`
    }
    
    type Conf struct {
        Subnet string `json:"Subnet"`
    }
    
    type Container struct {
        Name string `json:"Name"`
            EndPointID string `json:"EndpointID"`
        MacAddress string `json:"MacAddress"`
            IPv4Address string `json:"IPv4Address"`
        IPv6Address string `json:"IPv6Address"`
    }
    

    There's a few stuff I still have set to interface, that's just cause the sample json doesn't include any data for them so I can't know what their type should be in the Go source. Here's some basic stuff I also added in your main to test out the objects/make sure I had things defined correctly;

    docks := []DockerInstance{} //note you're using an array of the top level type
    err := json.Unmarshal([]byte(teststring), &docks)
    if err != nil {
        fmt.Println(err)
    } else {
        fmt.Println()
        fmt.Println()
        fmt.Println(docks[0].Name)
    }
    
    for k, v := range docks[0].Containers {
        fmt.Println(k)
        fmt.Println(v.IPv4Address)
    }
    
    for k, v := range docks[0].Options {
          fmt.Println(k)
        fmt.Println(v)
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 腾讯企业邮箱邮件可以恢复么
  • ¥15 有人知道怎么将自己的迁移策略布到edgecloudsim上使用吗?
  • ¥15 错误 LNK2001 无法解析的外部符号
  • ¥50 安装pyaudiokits失败
  • ¥15 计组这些题应该咋做呀
  • ¥60 更换迈创SOL6M4AE卡的时候,驱动要重新装才能使用,怎么解决?
  • ¥15 让node服务器有自动加载文件的功能
  • ¥15 jmeter脚本回放有的是对的有的是错的
  • ¥15 r语言蛋白组学相关问题
  • ¥15 Python时间序列如何拟合疏系数模型