たなしょのメモ

日々勉強していることをつらつらと

GoでJsonファイルを取り扱う際に苦労したのでメモ

Goを使って今書いているCLIのツールで設定ファイルをJsonで書いているのですが、
配列の中にネストされているJsonデータを取り扱いできない問題が発生したのでここに解決策をメモしておきます。

問題のJsonは下記のようなファイルです。

{
    "settingArray": [ 
        {
            "id": 1,
            "mainRepository": "/home/AutoBranchUpdate/src",
            "logRepository": "/home/AutoBranchUpdate/src",
            "masterBranch": "master",
            "logName": "sampleLog",
            "targetRepository": [
                "feature",
                "feature2"
            ]
        }
}

文字列配列のJsonファイルからデータを取り出す

まずは以下のJsonファイルからデータを取り出します。

{
    "testArray": [
        "a",
        "b",
        "c"
    ]
}

このような配列のみのJsonファイルの場合、Goで宣言する構造体は下記のようになります。

type Te struct {
    TestArray []string `json:"testArray"`
}

出力処理は下記のようになります。(ファイル名以外共通の出力処理です。以降は省略します。)

func main() {
    raw, err := ioutil.ReadFile("./test.json")
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    var test Te
    if err = json.Unmarshal(raw, &test); err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    fmt.Println(test)
}

実行結果は以下のようになり、データを取得できています。

{[a b c]}

複数のオブジェクトを配列でもっているJsonファイルのデータを取り出す

ここからが本題になります。
複数のオブジェクトを配列で持っている下記のようなJsonファイルからデータを取り出します。

{
    "testArray": [
        {
            "id": 1,
            "name": "test"
        },
        {
            "id": 2,
            "name": "tanaka"
        }
    ]
}

このような配列の場合、構造体の配列を宣言すれば解決できました。
Te2構造体はTestArrayフィールド持ちます。TestArrayフィールドの中身はData構造体の配列です。
Data構造体にはid, nameのフィールドを持っています。

type Te2 struct {
    TestArray []Data `json:"testArray"`
}

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

出力結果は下記のようになります。

{[{1 test} {2 tanaka}]}

複数(文字列配列も含む)のオブジェクトを配列でもっているJsonファイルのデータを取り出す

最初に提示した複数(文字列配列も含む)のオブジェクトを持っている下記のJsonファイルからデータを取り出します。

{
    "testArray": [
        {
            "id": 1,
            "name": "test",
            "notion": [
                "pochi",
                "pochi"
            ]
        },
        {
            "id": 2,
            "name": "tanaka",
            "notion": [
                "chi",
                "chi"
            ]
        }
    ]
}

先ほどの構造体とほぼ同じです。 追加点はData構造体にはNotionの文字列配列のフィールドを追加しました。

type Te3 struct {
    TestArray []Data2 `json:"testArray"`
}

type Data2 struct {
    Id     int      `json:"id"`
    Name   string   `json:"name"`
    Notion []string `json:"notion"`
}

出力結果は下記のようになります。

{[{1 test [pochi pochi]} {2 tanaka [chi chi]}]}

最初に提示したJsonファイルのデータを取り出す

これまで試してきた過程を含めてJsonファイルからデータを抜き出したい場合、
配列に含まれるオブジェクトを持つSettingData構造体を定義します。
上記SettingData構造体の配列をフィールドにもつSetting構造体を定義して準備OKです!

type SettingData struct {
    Id               int      `json:"id"`
    MainRepository   string   `json:"mainRepository"`
    LogRepository    string   `json:"logRepository"`
    MasterBranch     string   `json:"masterBranch"`
    LogName          string   `json:"logName"`
    TargetRepository []string `json:"targetRepository"`
}

type Setting struct {
    SettingArray []SettingData `json:"settingArray"`
}

出力結果は以下のようになり、データが取得できました!

{[{1 /home/AutoBranchUpdate/src /home/AutoBranchUpdate/src master sampleLog [feature feature2]}]}

まとめ

複数のオブジェクトを配列に持つjsonファイルの場合は、 配列内のオブジェクトの構造体を定義した後に、配列内のオブジェクトの構造体の配列を持つ構造体を定義することでデータを取り扱えました。