2016-10-03 2 views
0

私の質問はgolangでJSONファイルを解析することです。googleでJSONを解析する

具体的には、「docker network inspect bridge」というコマンドの出力をJSON形式で解析しようとしています。コマンドについては、ここで説明します。私の目標は、リストされたコンテナの "IPv4Address"のリストを取得することです。

私はこれを実行しようとしましたが、マップ[文字列]インタフェース{}を[文字列]文字列にマップすることに失敗しました。私のコードはここにある: - 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" 
     } 
    } 
] 

golangに、このようなJSONファイルを解析するための正しい方法は何ですか。私はタイプ変換を使ってみましたが、助けにはなりません。私は多くのことを試しましたが、最終的にはスニペットに示されているコードまでしか到達できませんでした。 "cont"オブジェクトからIPv4Addressフィールドを抽出するにはどうすればよいですか?

私が持っている遊び場スニペットへのリンクはhttps://play.golang.org/p/eO_j996gGbです。どんな助けも大いに評価されます(物事を試して喜んで、コードだけでなくアイディアが必要です:)ありがとう。

+0

More FYI:ほとんどのドッカーコマンドは、 'text/template'パッケージのGolangテンプレートである必要がある' --format'オプションを受け入れます。 – TheHippo

答えて

2

データをさらに展開するには、コードを変更する必要があります。 interface{}と表示されている各コンテナオブジェクトを残しておくと、そのコンテナオブジェクト内のフィールドにアクセスできなくなります。それぞれをmap[string]interface{}にすることをアサートすると、名前内のフィールドにアクセスできます(IPv4Addressなど)。ここに実例があります。 https://play.golang.org/p/4OC5axN4Gd

ここで重要なコード変更があります。

containers := (foo[0]["Containers"]).(map[string]interface{}) 

    //fmt.Printf("containers %+v", containers) 
    for _, v := range containers { 
     unwrapped := v.(map[string]interface{}) 
     fmt.Printf("\ncont %+v\n", unwrapped["IPv4Address"])    
    } 

vので、あなたがタイプに変換/再アサートせずにIPv4Addressフィールドにアクセスする方法がないだけinterface{}です。

これでうまくいきましたが、私はコード内のインターフェイスが大量に使用されることを避けることを推奨します。あなたのコードには、多くのエラー処理が必要な安全でない操作がたくさんあります(マップにアクセスしようとするたびに、投げられる可能性があり、いつでもタイプアサートを行うなど)。ここでこれを行う方法の例がたくさんありますが、コメントを要求しても、構造体に非マーシャルする別の例を作ることができます。すべてのパニックを引き起こす可能性のある結果を扱う多くのコードを潜在的に持つのではなく、ほとんどのエラーが非整列呼び出しの呼び出しで発生するため、これはずっと安全でメンテナンス可能です。

ここには、すべての型があり、非整列化を使用するいくつかのプレイコードがあります。 https://play.golang.org/p/VfHst9GaiR

あなたのタイプは次のように表すことができます。

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"` 
} 

私はまだインターフェイスに設定されているいくつかのものがあります、それはちょうど私がそのタイプが行くの源であるべきかを知ることができないので、サンプルJSONは、彼らのためにどのようなデータが含まれていない原因です。ここには、オブジェクトをテストするためにあなたのメインに追加した基本的なものや、正しく定義されたものがあることを確認するものもあります。

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) 
} 
+0

ありがとうございました。私は昨日のことを試している間、あなたのソリューションのようにコードに非常に近いところに来ましたが、時にはうまくいきませんでした:(はい、私はあなたがあなたの答えで説明したより安全な方法に興味があります。 JSON。もう一度ありがとう。 –

+0

実際、JSONを表す同等の構造体とその中に非整列化された構造体が必要です。あなたがいくつかの指針を与えるなら、私は自分自身でこれを試すことができます。ありがとう。 –

+1

@GauravSinhaうん、それは私が言っていることであり、ここにその例があります。 https://play.golang.org/p/VfHst9GaiR私はデータがそこにあることを証明するためにたくさんのちょっとしたやり方をしたけれど、それにアクセスする方法を示すために、関連するコードのいくつかを私の答えに投稿します。 – evanmcdonnal