🙆

GoでJSONから特定フィールドを抽出してJSONL形式に変換する方法

2025/03/22に公開

Go言語でJSONの中身の一部をバイト列として扱いながら、json.RawMessage と json.Compact を利用してJSONL形式へ変換・書き込む方法を解説します。

注:この記事は著者がChatGPTのo3-miniで出力したものを少しだけ編集した記事です。

サンプルJSON

今回使用するサンプルJSONは、全体情報とともに「data」フィールドに複数のオブジェクトが含まれている形式です。dataが配列であることが一目で分かるようになっています。以下は、2件のアイテムが格納されている例です。

{
  "totalCount": 2,
  "data": [
    {
      "id": "item1",
      "name": "Item One",
      "value": 100
    },
    {
      "id": "item2",
      "name": "Item Two",
      "value": 200
    }
  ]
}

JSONの中身をバイト列として扱うメリット

Go言語では、json.RawMessage を使用することで、JSONの一部をそのままのバイト列([]byte)として保持できます。

これにより、後から必要に応じて各オブジェクトを加工や整形することが容易になります。

また、json.Compact を使えば、不要な空白や改行を除去してコンパクトなJSONに変換でき、結果としてシンプルで軽量なJSONLファイルが生成されます。

実装例

以下のコード例では、シンプルなサンプルJSONを「sample.json」として読み込み、data配列内の各JSONオブジェクトをコンパクト化してバッファに書き込み、最後に io.Copy を使って一括出力する方法を示します。

package main

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

type Response struct {
	TotalCount int               `json:"totalCount"`
	Data       []json.RawMessage `json:"data"`
}

func main() {
	// 入力JSONファイルをオープン
	f, err := os.Open("sample.json")
	if err != nil {
		fmt.Println("読み込みエラー:", err)
		return
	}
	defer f.Close()

	// json.Decoder を用いてJSONをパース
	var resp Response
	dec := json.NewDecoder(f)
	if err := dec.Decode(&resp); err != nil {
		fmt.Println("パースエラー:", err)
		return
	}

	// 出力先のJSONLファイルを作成
	outFile, err := os.Create("output.jsonl")
	if err != nil {
		fmt.Println("ファイル作成エラー:", err)
		return
	}
	defer outFile.Close()

	// 全体のバッファをループの外で定義
	var buf bytes.Buffer

	// 各JSONオブジェクトをコンパクト化してバッファに書き込み、改行を追加
	for _, raw := range resp.Data {
		if err := json.Compact(&buf, raw); err != nil {
			fmt.Println("コンパクト化エラー:", err)
			continue
		}
		buf.WriteByte('\n')
	}

	// バッファの内容をファイルへ一括書き込み
	if _, err := io.Copy(outFile, &buf); err != nil {
		fmt.Println("書き込みエラー:", err)
		return
	}

	fmt.Println("JSONL形式での出力が完了しました。")
}

以下のJSONLが出力されます。

{"id":"item1","name":"Item One","value":100}
{"id":"item2","name":"Item Two","value":200}

コードの特徴

  • json.RawMessage によるバイト列保持
    Response構造体の data フィールドは []json.RawMessage として定義しており、data配列内の各オブジェクトをそのままバイト列として保持できます。後から json.Compact で簡単に整形できます。

  • グローバルなバッファを利用した一括書き込み
    ループの外で定義した bytes.Buffer に、各オブジェクトをコンパクト化して書き込み、最後に io.Copy を使ってバッファの内容を一括で出力するため、ディスクへの書き込み回数を減らし効率的なファイル生成が実現できます。

まとめ

この記事では、Go言語でJSONの内容の一部をバイト列として扱いながら、json.RawMessage と json.Compact を活用してJSONL形式へ変換する方法をご紹介しました。ぜひ活用してください。

Discussion