2013-06-17 22 views
59

WebからJSONデータを読み込もうとしていますが、そのコードは空の結果を返します。私はここで何が間違っているのか分かりません。GolangでJSON応答を取得する方法

package main 

import "os" 
import "fmt" 
import "net/http" 
import "io/ioutil" 
import "encoding/json" 

type Tracks struct { 
    Toptracks []Toptracks_info 
} 

type Toptracks_info struct { 
    Track []Track_info 
    Attr []Attr_info 
} 

type Track_info struct { 
    Name  string 
    Duration string 
    Listeners string 
    Mbid  string 
    Url  string 
    Streamable []Streamable_info 
    Artist  []Artist_info 
    Attr  []Track_attr_info 
} 

type Attr_info struct { 
    Country string 
    Page  string 
    PerPage string 
    TotalPages string 
    Total  string 
} 

type Streamable_info struct { 
    Text  string 
    Fulltrack string 
} 

type Artist_info struct { 
    Name string 
    Mbid string 
    Url string 
} 

type Track_attr_info struct { 
    Rank string 
} 

func get_content() { 
    // json data 
    url := "http://ws.audioscrobbler.com/2.0/?method=geo.gettoptracks&api_key=c1572082105bd40d247836b5c1819623&format=json&country=Netherlands" 

    res, err := http.Get(url) 

    if err != nil { 
     panic(err.Error()) 
    } 

    body, err := ioutil.ReadAll(res.Body) 

    if err != nil { 
     panic(err.Error()) 
    } 

    var data Tracks 
    json.Unmarshal(body, &data) 
    fmt.Printf("Results: %v\n", data) 
    os.Exit(0) 
} 

func main() { 
    get_content() 
} 

答えて

135

理想的な方法はioutil.ReadAllを使用するないあり、むしろ直接リーダーデコーダを使用します。 URLを取得し、その応答をtarget構造体にデコードする便利な関数があります。

var myClient = &http.Client{Timeout: 10 * time.Second} 

func getJson(url string, target interface{}) error { 
    r, err := myClient.Get(url) 
    if err != nil { 
     return err 
    } 
    defer r.Body.Close() 

    return json.NewDecoder(r.Body).Decode(target) 
} 

使用例:

type Foo struct { 
    Bar string 
} 

func main() { 
    foo1 := new(Foo) // or &Foo{} 
    getJson("http://example.com", foo1) 
    println(foo1.Bar) 

    // alternately: 

    foo2 := Foo{} 
    getJson("http://example.com", &foo2) 
    println(foo2.Bar) 
} 

あなたはこの答えとして生産のhttp.Client構造がもともと立証*デフォルトを使用すべきではありません! (これはhttp.Get/etcが呼び出すものです)。その理由は、デフォルトのクライアントにタイムアウトが設定されていないためです。リモートサーバーが応答しない場合、あなたは悪い一日を過ごすでしょう。

+0

これは非常に役に立ちました。目標を得るにはしばらく時間がかかりましたが、私はまだ新しいです。 '' 'tmp:= myStuct {}' '' '' '' 'json.NewDecoder(r.Body).Decode(&tmp)' ''という構造体を作成し、そこからjsonを使うことができました。 – mvndaai

+4

構造体のアイテムの名前に大文字を使用する必要があるようです。'型WebKeys構造体{ \tキー[]構造体{ \t \t X5tストリング \t \t X5c []ストリング \t}}'あなたが解析しているJSONにおける実際のparamsは小文字である場合であっても。 JSON例: '{ \t "キー":[{ \t \t "x5t": "FOO"、 \t \t "x5c": "baaaar" \t}] }' – Wilson

+0

正解です。 'encoding/json'は宣言されているパッケージの外側で小文字のキーにアクセスすることはできません。 –

10

jsonパッケージで使用するには、構造体に大文字のプロパティ名が必要です。

大文字のプロパティ名はexported propertiesです。小文字のプロパティ名はエクスポートされません。

また、参照(&data)でデータオブジェクトを渡す必要があります。

package main 

import "os" 
import "fmt" 
import "net/http" 
import "io/ioutil" 
import "encoding/json" 

type tracks struct { 
    Toptracks []toptracks_info 
} 

type toptracks_info struct { 
    Track []track_info 
    Attr []attr_info 
} 

type track_info struct { 
    Name  string 
    Duration string 
    Listeners string 
    Mbid  string 
    Url  string 
    Streamable []streamable_info 
    Artist  []artist_info 
    Attr  []track_attr_info 
} 

type attr_info struct { 
    Country string 
    Page  string 
    PerPage string 
    TotalPages string 
    Total  string 
} 

type streamable_info struct { 
    Text  string 
    Fulltrack string 
} 

type artist_info struct { 
    Name string 
    Mbid string 
    Url string 
} 

type track_attr_info struct { 
    Rank string 
} 

func get_content() { 
    // json data 
    url := "http://ws.audioscrobbler.com/2.0/?method=geo.gettoptracks&api_key=c1572082105bd40d247836b5c1819623&format=json&country=Netherlands" 

    res, err := http.Get(url) 

    if err != nil { 
     panic(err.Error()) 
    } 

    body, err := ioutil.ReadAll(res.Body) 

    if err != nil { 
     panic(err.Error()) 
    } 

    var data tracks 
    json.Unmarshal(body, &data) 
    fmt.Printf("Results: %v\n", data) 
    os.Exit(0) 
} 

func main() { 
    get_content() 
} 
+0

まだ動作しませんが、これはあなたのために機能しますか?同じ空の応答 – GOD

+1

"jsonパッケージで使用するには、構造体に大文字のプロパティ名が必要です。" – HVNSweeting

18

あなたの問題は、(Trackを除いて、彼らはスライスすべきではない...)structsあなたのデータにスライス宣言しました。これは、フェッチされたjsonファイル内のいくつかのグーフィーフィールド名によって複合化されました。これはstructタグで修正できます。godocを参照してください。

以下のコードはjsonを正常に解析しました。さらなる質問がある場合は、私に教えてください。 json.Unmarshalvar data interface{}へ)から

package main 

import "fmt" 
import "net/http" 
import "io/ioutil" 
import "encoding/json" 

type Tracks struct { 
    Toptracks Toptracks_info 
} 

type Toptracks_info struct { 
    Track []Track_info 
    Attr Attr_info `json: "@attr"` 
} 

type Track_info struct { 
    Name  string 
    Duration string 
    Listeners string 
    Mbid  string 
    Url  string 
    Streamable Streamable_info 
    Artist  Artist_info 
    Attr  Track_attr_info `json: "@attr"` 
} 

type Attr_info struct { 
    Country string 
    Page  string 
    PerPage string 
    TotalPages string 
    Total  string 
} 

type Streamable_info struct { 
    Text  string `json: "#text"` 
    Fulltrack string 
} 

type Artist_info struct { 
    Name string 
    Mbid string 
    Url string 
} 

type Track_attr_info struct { 
    Rank string 
} 

func perror(err error) { 
    if err != nil { 
     panic(err) 
    } 
} 

func get_content() { 
    url := "http://ws.audioscrobbler.com/2.0/?method=geo.gettoptracks&api_key=c1572082105bd40d247836b5c1819623&format=json&country=Netherlands" 

    res, err := http.Get(url) 
    perror(err) 
    defer res.Body.Close() 

    decoder := json.NewDecoder(res.Body) 
    var data Tracks 
    err = decoder.Decode(&data) 
    if err != nil { 
     fmt.Printf("%T\n%s\n%#v\n",err, err, err) 
     switch v := err.(type){ 
      case *json.SyntaxError: 
       fmt.Println(string(body[v.Offset-40:v.Offset])) 
     } 
    } 
    for i, track := range data.Toptracks.Track{ 
     fmt.Printf("%d: %s %s\n", i, track.Artist.Name, track.Name) 
    } 
} 

func main() { 
    get_content() 
} 
+1

レスポンスボディに何かがあります。 – peterSO

+4

私の場合は、 "構造体"フィールドに大文字の最初の文字がありませんでした。 – abourget

+0

以下は正しい答えです.Dodyをレスポンスに直接使用してください.Bodyは不要な割り当てを避け、一般的にもっと理想的です。私の答えを訂正しました。それを指摘してくれてありがとう。 – tike

6

結果が直接あなたの囲碁タイプと変数の宣言と一致しません。例えば、

package main 

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

type Tracks struct { 
    Toptracks []Toptracks_info 
} 

type Toptracks_info struct { 
    Track []Track_info 
    Attr []Attr_info 
} 

type Track_info struct { 
    Name  string 
    Duration string 
    Listeners string 
    Mbid  string 
    Url  string 
    Streamable []Streamable_info 
    Artist  []Artist_info 
    Attr  []Track_attr_info 
} 

type Attr_info struct { 
    Country string 
    Page  string 
    PerPage string 
    TotalPages string 
    Total  string 
} 

type Streamable_info struct { 
    Text  string 
    Fulltrack string 
} 

type Artist_info struct { 
    Name string 
    Mbid string 
    Url string 
} 

type Track_attr_info struct { 
    Rank string 
} 

func get_content() { 
    // json data 
    url := "http://ws.audioscrobbler.com/2.0/?method=geo.gettoptracks&api_key=c1572082105bd40d247836b5c1819623&format=json&country=Netherlands" 
    url += "&limit=1" // limit data for testing 
    res, err := http.Get(url) 
    if err != nil { 
     panic(err.Error()) 
    } 
    body, err := ioutil.ReadAll(res.Body) 
    if err != nil { 
     panic(err.Error()) 
    } 
    var data interface{} // TopTracks 
    err = json.Unmarshal(body, &data) 
    if err != nil { 
     panic(err.Error()) 
    } 
    fmt.Printf("Results: %v\n", data) 
    os.Exit(0) 
} 

func main() { 
    get_content() 
} 

出力:

Results: map[toptracks:map[track:map[name:Get Lucky (feat. Pharrell Williams) listeners:1863 url:http://www.last.fm/music/Daft+Punk/_/Get+Lucky+(feat.+Pharrell+Williams) artist:map[name:Daft Punk mbid:056e4f3e-d505-4dad-8ec1-d04f521cbb56 url:http://www.last.fm/music/Daft+Punk] image:[map[#text:http://userserve-ak.last.fm/serve/34s/88137413.png size:small] map[#text:http://userserve-ak.last.fm/serve/64s/88137413.png size:medium] map[#text:http://userserve-ak.last.fm/serve/126/88137413.png size:large] map[#text:http://userserve-ak.last.fm/serve/300x300/88137413.png size:extralarge]] @attr:map[rank:1] duration:369 mbid: streamable:map[#text:1 fulltrack:0]] @attr:map[country:Netherlands page:1 perPage:1 totalPages:500 total:500]]] 
関連する問題