2013年3月9日土曜日

Go言語でJSONを扱う


こんにちは。scarvizです。

先月にAndroidのアプリコンテストにエントリーしたのですが、その時に経路情報とかGCMとかを使う上で、JSONを触りました。
実は初めてちゃんとJSONに触れたんですね。
結構面白かったので、Go言語でもJSONやってみました。

基本的にここの内容の前半と同じです。
http://golang.org/doc/articles/json_and_go.html



■JSONの構造体
JSON用に構造体を用意します。
今回は以下を用意しました。

type Message struct {
 Id   int64
 Data string
}

ここで気をつける点は、要素名の頭文字を大文字にしてエクスポートしておかないといけない点です。
うっかり小文字にしてて僕ははまってました・・・。

テストデータとしては以下を用意しました。

mes := Message{1, "JSONTest"}

■エンコーディング
エンコーディングはjson.Marshalを使用します。
引数はinterface型になっています。なので、構造体をそのまま渡します。

package main

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

type Message struct {
 Id   int64
 Data string
}

func main() {
 mes := Message{1, "JSONTest"}

 // JSONにエンコーディングする
 bdata := EncodingJSON(mes)
 // byteスライスを出力する
 os.Stdout.Write(bdata)
}

/*
JSONにエンコーディングする
*/
func EncodingJSON(mes Message) []byte {
 bdata, err := json.Marshal(mes)

 if err != nil {
  fmt.Println(err)
  return nil
 }

 return bdata
}

結果:
{"Id":1,"Data":"JSONTest"}


■デコーディング
デコーディングはjson.Unmarshalを使用します。
第一引数にbyteスライス(JSON)を渡し、第二引数には構造体を参照渡しします。

package main

import (
 "encoding/json"
 "fmt"
)

type Message struct {
 Id   int64
 Data string
}

func main() {
 mes := Message{1, "JSONTest"}
 // JSONにエンコーディングする
 bdata, _ := json.Marshal(mes)
 
 // JSONをデコーディングする
 dmes := DecodingJSON(bdata)
 // 構造体を出力する
 fmt.Println(dmes)
}

/*
JSONにデコーディングする
*/
func DecodingJSON(bdata []byte) Message {
 var mes Message

 err := json.Unmarshal(bdata, &mes)

 if err != nil {
  fmt.Println(err)
  return Message{-1, "err"}
 }

 return mes
}

結果:
{1 JSONTest}

デコーディング時にJSONのキーは大文字小文字を区別しないそうです。
DataでもDATAでもDaTaでもdaTaでも全部同じものとして扱います。
また、構造体に定義している要素がJSONのキーに無い場合は、ゼロ値が格納されます。
逆にJSONのキーにあって、構造体に定義していないものがある場合は、その値は無視されます。

package main

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

type Message struct {
 Id   int64
 Data string
}

func main() {
 // JSONのキーが"DaTa"になってる場合
 bdata1 := []byte(`{"Id":1,"DaTa":"JSONTest"}`)
 os.Stdout.Write(bdata1)
 fmt.Println("")
 
 // JSONをデコーディングする
 dmes1 := DecodingJSON(bdata1)
 // 構造体を出力する
 fmt.Println(dmes1)
 fmt.Println("")
 
 // JSONにIdがない場合
 bdata2 := []byte(`{"DaTa":"JSONTest"}`)
 os.Stdout.Write(bdata2)
 fmt.Println("")
 
 // JSONをデコーディングする
 dmes2 := DecodingJSON(bdata2)
 // 構造体を出力する
 fmt.Println(dmes2)
 fmt.Println("")
 
 // JSONにTestという構造体で定義されていないキーが存在している場合
 bdata3 := []byte(`{"Id":1,"DaTa":"JSONTest","Test":"Test"}`)
 os.Stdout.Write(bdata3)
 fmt.Println("")
 
 // JSONをデコーディングする
 dmes3 := DecodingJSON(bdata3)
 // 構造体を出力する
 fmt.Println(dmes3)
}

/*
JSONにデコーディングする
*/
func DecodingJSON(bdata []byte) Message {
 var mes Message

 err := json.Unmarshal(bdata, &mes)

 if err != nil {
  fmt.Println(err)
  return Message{-1, "err"}
 }

 return mes
}

結果:
{"Id":1,"DaTa":"JSONTest"}
{1 JSONTest}

{"DaTa":"JSONTest"}
{0 JSONTest}

{"Id":1,"DaTa":"JSONTest","Test":"Test"}
{1 JSONTest}


■構造体の構造体
golang.orgのjson_and_goの後半には構造体の中に構造体を使用する方法もあったので紹介します。
構造体の中に構造体を使用する場合は次のように構造体のポインタ型で定義します。

package main

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

type Message struct {
 Id   int64
 Data *Datas
}

type Datas struct {
 TestData1 string
 TestData2 string
}

func main() {
 mes := Message{1, &Datas{"JSONTest1","JSONTest2"}}
 // JSONにエンコーディングする
 bdata := EncodingJSON(mes)
 // byteスライスを出力する
 os.Stdout.Write(bdata)
 fmt.Println("")

 // JSONをデコーディングする
 dmes := DecodingJSON(bdata)
 // 構造体を出力する
 fmt.Printf("Id:%d, [Data]TestData1:%s, TestData2:%s",
 dmes.Id, dmes.Data.TestData1, dmes.Data.TestData2)
 fmt.Println("")
}

/*
JSONにエンコーディングする
*/
func EncodingJSON(mes Message) []byte {
 bdata, err := json.Marshal(mes)

 if err != nil {
  fmt.Println(err)
  return nil
 }

 return bdata
}

/*
JSONにデコーディングする
*/
func DecodingJSON(bdata []byte) Message {
 var mes Message

 err := json.Unmarshal(bdata, &mes)

 if err != nil {
  fmt.Println(err)
  return Message{-1, nil}
 }

 return mes
}

結果:
{"Id":1,"Data":{"TestData1":"JSONTest1","TestData2":"JSONTest2"}}
Id:1, [Data]TestData1:JSONTest1, TestData2:JSONTest2



golang.orgのjson_and_goの後半には他にも、JSONの構造が予め分かっていない場合とか、1行ずつ読み書きする方法とかも書いてますが、省略します。
今回最初に作成したエンコーディング・デコーディングのソースを以下に置いています。
http://goo.gl/sh7sO

0 件のコメント:

コメントを投稿