【Go言語】JSONファイルからデータを読み込む

【初投稿】
投稿者は初めてQiitaに記事を投稿ですので，読みづらい箇所もあるかもしれませんが、どうぞご容赦いただけますと幸いです。

【記事について】
この記事は投稿者が学んだ技術について記述しております．中には誤っている部分もあるかもしれませんが、どうぞご容赦ください．

# はじめに
この記事では，Go言語におけるJSONファイルの読み込み方法について紹介させていただきます．

# 環境
macOS Monterey (バージョン 12.6.7)
go version go1.20.3 darwin/arm64

# JSONファイルとは？
JavaScript Object Notation（JSON、ジェイソン）はデータ記述言語の1つである．軽量なテキストベースのデータ交換用フォーマットでありプログラミング言語を問わず利用できる．名称と構文はJavaScriptにおけるオブジェクトの表記法に由来する．
([wikipedia](https://ja.wikipedia.org/wiki/JavaScript_Object_Notation#cite_note-1 "Wikipedia-JavaScript Object Notation")より引用)

JSONファイルの記述形式は，{}で括られているマップ(辞書)の形式のものと，[]で括られているリスト(配列)形式のものがあります．下記の図は辞書形式のユーザ情報がリストに格納されているJSONファイルの例です．
(こちらの[こちら](https://e-words.jp/w/JSON%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB.html "e-word:JSONファイル")で詳しく説明されております)
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/500067/0026ea6b-4765-4943-6479-c128609c6ad2.png">

# 実際に取り出してみる
## 使用するJSONファイルについて
今回はChatGPTに作成してもらった日本の都道府県の都道府県名，県庁所在地，人口のJSONファイルのデータを読み込んでみます．

<details><summary>今回使用したJSONファイル</summary>

```json:PrefecturesOfJapan.json
{
    "prefectures":
    [
        {
            "name": "北海道",
            "capital": "札幌市",
            "population": 5267762
        },
        {
            "name": "青森県",
            "capital": "青森市",
            "population": 1227505
        },
        {
            "name": "岩手県",
            "capital": "盛岡市",
            "population": 1274529
        },
        {
            "name": "宮城県",
            "capital": "仙台市",
            "population": 2342187
        },
        {
            "name": "秋田県",
            "capital": "秋田市",
            "population": 965643
        },
        {
            "name": "山形県",
            "capital": "山形市",
            "population": 1121117
        },
        {
            "name": "福島県",
            "capital": "福島市",
            "population": 1875384
        },
        {
            "name": "茨城県",
            "capital": "水戸市",
            "population": 2887105
        },
        {
            "name": "栃木県",
            "capital": "宇都宮市",
            "population": 1962119
        },
        {
            "name": "群馬県",
            "capital": "前橋市",
            "population": 1973115
        },
        {
            "name": "埼玉県",
            "capital": "さいたま市",
            "population": 7314813
        },
        {
            "name": "千葉県",
            "capital": "千葉市",
            "population": 6222666
        },
        {
            "name": "東京都",
            "capital": "東京",
            "population": 13942856
        },
        {
            "name": "神奈川県",
            "capital": "横浜市",
            "population": 9200166
        },
        {
            "name": "新潟県",
            "capital": "新潟市",
            "population": 2250898
        },
        {
            "name": "富山県",
            "capital": "富山市",
            "population": 1046102
        },
        {
            "name": "石川県",
            "capital": "金沢市",
            "population": 1154008
        },
        {
            "name": "福井県",
            "capital": "福井市",
            "population": 767287
        },
        {
            "name": "山梨県",
            "capital": "甲府市",
            "population": 832832
        },
        {
            "name": "長野県",
            "capital": "長野市",
            "population": 2098804
        },
        {
            "name": "岐阜県",
            "capital": "岐阜市",
            "population": 2031903
        },
        {
            "name": "静岡県",
            "capital": "静岡市",
            "population": 3700305
        },
        {
            "name": "愛知県",
            "capital": "名古屋市",
            "population": 7555393
        },
        {
            "name": "三重県",
            "capital": "津市",
            "population": 1815865
        },
        {
            "name": "滋賀県",
            "capital": "大津市",
            "population": 1412916
        },
        {
            "name": "京都府",
            "capital": "京都市",
            "population": 2585889
        },
        {
            "name": "大阪府",
            "capital": "大阪市",
            "population": 8824569
        },
        {
            "name": "兵庫県",
            "capital": "神戸市",
            "population": 5534800
        },
        {
            "name": "奈良県",
            "capital": "奈良市",
            "population": 1364316
        },
        {
            "name": "和歌山県",
            "capital": "和歌山市",
            "population": 964211
        },
        {
            "name": "鳥取県",
            "capital": "鳥取市",
            "population": 555633
        },
        {
            "name": "島根県",
            "capital": "松江市",
            "population": 671159
        },
        {
            "name": "岡山県",
            "capital": "岡山市",
            "population": 1914042
        },
        {
            "name": "広島県",
            "capital": "広島市",
            "population": 2830410
        },
        {
            "name": "山口県",
            "capital": "山口市",
            "population": 1362002
        },
        {
            "name": "徳島県",
            "capital": "徳島市",
            "population": 740397
        },
        {
            "name": "香川県",
            "capital": "高松市",
            "population": 985842
        },
        {
            "name": "愛媛県",
            "capital": "松山市",
            "population": 1385262
        },
        {
            "name": "高知県",
            "capital": "高知市",
            "population": 694206
        },
        {
            "name": "福岡県",
            "capital": "福岡市",
            "population": 5147740
        },
        {
            "name": "佐賀県",
            "capital": "佐賀市",
            "population": 819959
        },
        {
            "name": "長崎県",
            "capital": "長崎市",
            "population": 1335869
        },
        {
            "name": "熊本県",
            "capital": "熊本市",
            "population": 1786170
        },
        {
            "name": "大分県",
            "capital": "大分市",
            "population": 1166338
        },
        {
            "name": "宮崎県",
            "capital": "宮崎市",
            "population": 1087802
        },
        {
            "name": "鹿児島県",
            "capital": "鹿児島市",
            "population": 1617138
        },
        {
            "name": "沖縄県",
            "capital": "那覇市",
            "population": 1465613
        }
    ]
}

```
</details>

## 今回のメインとなる二つのパッケージ
### embed
Go言語にはembedというパッケージがあり，こちらを用いることで簡単にファイルを読み込むことができます．
>Package embed provides access to files embedded in the running Go program.
(embedパッケージは，実行中のGoプログラムに埋め込まれたファイルへのアクセスを提供します．- DeepLで和訳)
([go:embed](https://pkg.go.dev/embed "go:embed")より引用)



### encording/json
今回はJSONファイルからデータを読み込みます．jsonパッケージでは，RFC7159で定義されているJSONのエンコードとデコードが実装されており，データを解析し構造体にデータを格納することができます．

>Package json implements encoding and decoding of JSON as defined in RFC 7159. The mapping between JSON and Go values is described in the documentation for the Marshal and Unmarshal functions.
(jsonパッケージは，RFC 7159で定義されているJSONのエンコードとデコードを実装しています．JSONとGoの値の対応付けは，Marshal関数とUnmarshal関数のドキュメントで説明されています．- DeepLで和訳)
([go:encording/json](https://pkg.go.dev/encoding/json "go:encording/json"))

## コードの説明
#### ファイルからデータを読み込む(embed)
はじめに，embedを用いてPrefecturesOfJapan.jsonをbyte型のリストで読み込みます．


```go:prefecture.go(ファイルからデータを読み込む)
//go:embed "PrefecturesOfJapan.json"
var PrefecturesOfJapan []byte
```

#### 読み込んだデータを格納する構造体を定義する(encording/json)
次に読み込んだデータを格納する構造体を定義します．
構造体とJSONファイルの入れ子状態が一致していることに注目してください．
今回用いたPrefecturesOfJapan.jsonは，辞書形式の都道府県の情報がprefecturesというリストに格納されています． 今回は，都道府県の情報をPrefectureInfという名前の構造体で定義し，prefecturesというリストはPrefectureという名前の構造体で定義し，PrefectureInf型のリストをprefectureという名前で持っています．

```go:prefecture.go（データを格納する構造体を定義する）
// データを格納する構造体を定義する
type Prefectures struct {
	Prefecture []*PrefectureInf `json:"prefectures"`
}

type PrefectureInf struct {
	Name       string `json:"name"`
	Capital    string `json:"capital"`
	Population int    `json:"population"`
}
```
```json:PrefecturesOfJapan.json (北海道だけver)
{
    "prefectures":
    [
        {
            "name": "北海道",
            "capital": "札幌市",
            "population": 5267762
        }
    ]
}
```


### データを解析して，構造体に格納する
encording/jsonのUnmarshalを用いてデータを解析して構造体に格納します．
```go:prefecture.go(データ解析→構造体に格納)
	// prefectureという名前のPrefecturesの構造体を作成する
	prefecture := Prefectures{}

	// データを解析して，構造体に格納する
	err := json.Unmarshal(PrefecturesOfJapan, &prefecture)

	// エラーが出た場合はエラーメッセージを出力し，1を返して終了させる
	if err != nil {
		fmt.Println(err.Error())
		return 1
	}
```

### データを出力して確認
最後に格納したデータを出力して確認を行います．
全て出力すると見づらいため，下記のコードでは格納した順で10個だけ確認するようになっています．
```go:prefecture.go（データの出力）
	// データを出力する(上から10個だけ)
	for i, j := range prefecture.Prefecture {
		fmt.Printf("%s, %s, %d\n", j.Name, j.Capital, j.Population)
		if i == 10 {
			fmt.Print("    ・\n    ・\n    ・\n")
			break
		}
	}
	return 0
```

## 実際に作成したプログラムと実行結果
下記に実際に作成したプログラムとその実行結果をしまします．

```go:prefecture.go
package main

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

//go:embed "PrefecturesOfJapan.json"
var PrefecturesOfJapan []byte

// データを格納する構造体を定義する
type Prefectures struct {
	Prefecture []*PrefectureInf `json:"prefectures"`
}

type PrefectureInf struct {
	Name       string `json:"name"`
	Capital    string `json:"capital"`
	Population int    `json:"population"`
}

func goMain() int {
	// prefectureという名前のPrefecturesの構造体を作成する
	prefecture := Prefectures{}

	// データを解析して，構造体に格納する
	err := json.Unmarshal(PrefecturesOfJapan, &prefecture)

	// エラーが出た場合はエラーメッセージを出力し，1を返して終了させる
	if err != nil {
		fmt.Println(err.Error())
		return 1
	}

	// データを出力する(上から10個だけ)
	for i, j := range prefecture.Prefecture {
		fmt.Printf("%s, %s, %d\n", j.Name, j.Capital, j.Population)
		if i == 10 {
			fmt.Print("    ・\n    ・\n    ・\n")
			break
		}
	}
	return 0
}
func main() {
	status := goMain()
	os.Exit(status)
}
```

```terminal:実行結果
$ go run prefectures.go 
北海道, 札幌市, 5267762
青森県, 青森市, 1227505
岩手県, 盛岡市, 1274529
宮城県, 仙台市, 2342187
秋田県, 秋田市, 965643
山形県, 山形市, 1121117
福島県, 福島市, 1875384
茨城県, 水戸市, 2887105
栃木県, 宇都宮市, 1962119
群馬県, 前橋市, 1973115
埼玉県, さいたま市, 7314813
    ・
    ・
    ・
```

# まとめ
今回はGo言語における，JSONファイルからデータを読み込む方法について紹介させていただきました．
冒頭でも述べた通り，この投稿は初投稿であり，私もまだまだ学習している身ですので，読みにくかったり，誤りがあるとは思いますがご容赦ください．こちらの記事を参考にする際は，念のために<font color="Red">**一次資料**</font>や<font color="Red">**二次資料**</font>を閲覧されることをお勧めいたします．

[Go言語の一次資料](https://go.dev/"go.dev")