LoginSignup
0
2

More than 1 year has passed since last update.

Go標準パッケージを利用したJsonデータの読み込み&出力

Last updated at Posted at 2022-11-18

概要

JSONの読み込みは「json.Unmarshal」「json.NewDecoder」の2種類、JSONの生成は「json.Marshal」「json.Marshalindent」「json.NewDecoder」の3種類を使った方法を紹介する。

encoding/jsonパッケージ

JSONデータのエンコードとデコードをするためのパッケージ。
今回はこのパッケージを使用してJSONデータの解析を行う。

JSONデータの読み込み

json.Unmarshal

json.Unmarshal()はJSONを構造体に変換する。
第一引数にJSON形式のデータを、第二引数にポインタを指定することでJSON形式で受け取った値を指定したポインタに保存することができる。

json.Unmarshal(JSON形式のデータ, ポインタ)

JSONデータを解析してみる

今回は以下のようなJSONデータを用意する。ファイルの名前はtest.jsonとする。

{
  "id" : 1,
  "content" : "Hello World!",
  "author" : {
    "id" : 2,
    "name" : "Goromaru"
  },
  "comments" : [
    {
      "id" : 1,
      "content" : "Rugby is great sport",
      "author" : "Matsushima"
    },
    {
      "id" : 2,
      "content" : "Try!!",
      "author" : "Fukuoka"
    }
  ]
}

以下がJSONデータを解析するコード。test.jsonは同じ階層にあるものとする。

package main

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

type Post struct {
	Id       int       `json:"id"`
	Content  string    `json:"content"`
	Author   Author    `json:"author"`
	Comments []Comment `json:"comments"`
}

type Author struct {
	Id   int    `json:"id"`
	Name string `json:"name"`
}

type Comment struct {
	Id      int    `json:"id"`
	Content string `json:"content"`
	Author  string `json:"author"`
}

func main() {
	jsonFile, err := os.Open("test.json")
	if err != nil {
		fmt.Println("JSONファイルを開けません", err)
		return
	}
	defer jsonFile.Close()
	jsonData, err := ioutil.ReadAll(jsonFile)
	if err != nil {
		fmt.Println("JSONデータを読み込めません", err)
		return
	}

	var post Post
	json.Unmarshal(jsonData, &post)

	fmt.Println(post)
	fmt.Println(post.Comments)
	fmt.Println(post.Comments[0].Content)

}

ポイント

  • まずos.Open()を使ってJSONファイルを開き、ioutil.ReadAll()で読み込む。
  • 解析したJSONの情報を保存するための構造体を作成する必要がある。一番大きな枠組みとして構造体Postを定義している。
  • test.jsonのauthorはキー・バリュー形式になっているので別途、構造体Authorを定義する。構造体PostのAuthorフィールドはAuthor型となる。
  • test.jsonのcommentsはスライスになっているので、別途、構造体Commentを定義する。構造体PostのCommentsフィールドはComment型のデータを格納するスライスとする。
  • json.Unmarshal(jsonData, &post)で読み込んだtest.jsonの情報を構造体postに格納している。
  • fmt.Println(post)は以下のようになる。
{1 Hello World! {2 Goromaru} [{1 Rugby is great sport Matsushima} {2 Try!! Fukuoka}]}
  • fmt.Println(post.Comments)は以下のようになる。
[{1 Rugby is great sport Matsushima} {2 Try!! Fukuoka}]
  • fmt.Println(post.Comments[0].Content)は以下のようになる。
Rugby is great sport

json.NewDecoderを使った読み込み方法

もう1つ、json.NewDecoder()を使う方法がある。
使い分けとしては、ストリームから情報を読み込んだ時はjson.NewDecoder()を、それ以外はjson.Unmarshal()を使うことになる。
json.NewDecoder()は例えば上記のtest.jsonに複数のJSONが含まれていても対応できるが、json.Unmarshal()は対応できない。

test.jsonを以下のように書き換えてみる。

{
  "id" : 1,
  "content" : "Hello World!",
  "author" : {
    "id" : 2,
    "name" : "Goromaru"
  },
  "comments" : [
    {
      "id" : 1,
      "content" : "Rugby is great sport",
      "author" : "Matsushima"
    },
    {
      "id" : 2,
      "content" : "Try!!",
      "author" : "Fukuoka"
    }
  ]
}

{
  "id" : 2,
  "content" : "Hahahahaha",
  "author" : {
    "id" : 3,
    "name" : "Nakamura"
  },
  "comments" : [
    {
      "id" : 1,
      "content" : "Rugby is brilliant",
      "author" : "Yamanaka"
    },
    {
      "id" : 2,
      "content" : "Scrum!!",
      "author" : "Inagaki"
    }
  ]
}

json.Unmarshal()を使って解析しようとするとエラーが出る。

package ファイル名 is not in GOROOT (xxx/..../test.json)

json.NewDecoder()使用した場合以下のようになる。
※構造体の定義など重複する部分は省略。


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

func main() {
	jsonFile, err := os.Open("test.json")
	if err != nil {
		fmt.Println("JSONファイルを開けません", err)
		return
	}
	defer jsonFile.Close()

	decoder := json.NewDecoder(jsonFile)
	for {
		var post Post
		err := decoder.Decode(&post)
		if err == io.EOF {
			break
		}
		if err != nil {
			fmt.Println("JSONデータを読み込めません", err)
			return
		}
		fmt.Println(post)
	}
}

ポイント

  • decoder := json.NewDecoder(jsonFile)でファイルを読み出し、for文でdecoder.Decode(&post)を実行することで構造体postにJSONデータを格納する。
  • 出力結果は以下のようになる。
{1 Hello World! {2 Goromaru} [{1 Rugby is great sport Matsushima} {2 Try!! Fukuoka}]}
{2 Hahahahaha {3 Nakamura} [{1 Rugby is brilliant Yamanaka} {2 Scrum!! Inagaki}]}

JSONデータの生成

json.Marsharl

json.Marsharl()はJSONを生成する。json.Marsharl()はJSONを整形しないで1行で出力する。

package main

import (
	"encoding/json"
	"fmt"
)

type Post struct {
	Id       int       `json:"id"`
	Content  string    `json:"content"`
	Author   Author    `json:"author"`
	Comments []Comment `json:"comments"`
}

type Author struct {
	Id   int    `json:"id"`
	Name string `json:"name"`
}

type Comment struct {
	Id      int    `json:"id"`
	Content string `json:"content"`
	Author  string `json:"author"`
}

func main() {
  post := Post{
    Id:      1,
    Content: "Hello World!",
    Author: Author{
      Id:   2,
      Name: "Goromaru",
    },
    Comments: []Comment{
      Comment{
        Id:      3,
        Content: "Rugby is great sport",
        Author:  "Matsushima",
      },
      Comment{
        Id:      4,
        Content: "Try!!",
        Author:  "Fukuoka",
      },
    },
  }

	output, err := json.Marshal(&post)
	if err != nil {
		fmt.Println("Error marshalling to JSON:", err)
		return
	}
	fmt.Println(string(output))
}
  • post := Post{…}の形でJSONの内容を作成する。作成したいJSONの構造そのままに書けば良いのでそんなに難しくはない。
  • output, err := json.Marshal(&post)のようにpostへのポインタを渡すと、JSONを生成してくれる。
  • 以下のように出力される。
{"id":1,"content":"Hello World!","author":{"id":2,"name":"Goromaru"},"comments":[{"id":3,"content":"Rugby is great sport","author":"Matsushima"},{"id":4,"content":"Try!!","author":"Fukuoka"}]}

json.MarshalIndent

json.MarshalIndent()はJSONを整形して出力する。以下のように使う。

json.MarshalIndent(jsonを作成した構造体のポインタ, 各行の先頭につけるプレフィックス, インデント)

上記のoutput, err := json.Marshal(&post)を以下のように変えるだけ。

output, err := json.MarshalIndent(&post, "", "\t\t")

ポイント

  • ファイルに書き出したり、コマンドラインに出力する時はこちらの方が良いだろう。
  • 以下のようなきれいな出力になる。
{
		"id": 1,
		"content": "Hello World!",
		"author": {
				"id": 2,
				"name": "Goromaru"
		},
		"comments": [
				{
						"id": 3,
						"content": "Rugby is great sport",
						"author": "Matsushima"
				},
				{
						"id": 4,
						"content": "Try!!",
						"author": "Fukuoka"
				}
		]
}

json.NewDecoderを使った解析方法

こちらもまた、json.NewDecoder()を使ってJSONの生成ができる。
以下のように使う。※重複部分は省略している。

err := json.NewEncoder(os.Stdout).Encode(post)
if err != nil {
	fmt.Println("Error encoding JSON to file:", err)
	return
}
  • json.NewEncoder()は引数で指定された場所にJSONを出力する。この場合は標準出力している。
  • .Encode(post)でPost構造体をエンコードしている。
  • 以下のような出力になる。
{"id":1,"content":"Hello World!","author":{"id":2,"name":"Goromaru"},"comments":[{"id":3,"content":"Rugby is great sport","author":"Matsushima"},{"id":4,"content":"Try!!","author":"Fukuoka"}]}
0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2