5.0 KiB
Architecture
dataxl は、ファイル形式ごとの差を小さくするために、内部表現を2つに分けています。
- structured value: JSON/YAML/TOMLから読める
map[string]any,[]any, scalar - table: Excel/CSV/TSVに近い
Header []stringとRows [][]string
変換は原則として次のどれかです。
- structured -> structured
- structured -> table
- table -> structured
- table -> table
Source Layout
実装は cmd/dataxl package内で責務別に分割しています。
main.go: CLI option、stdin/stdout、ファイル入出力conversion.go: 変換経路の選択、形式名の正規化・推定structured.go: JSON/YAML/TOML adaptertable.go: CSV/TSV/XLSX adapter、table model、flattenpath.go: セル値の型推定、列パスのparse、unflatten
convert はファイル入出力から独立しているため、CLIを経由せず変換matrixをテストできます。
形式固有処理は parseStructured / encodeStructured または
parseTable / encodeTable に閉じ込めます。
現状は単一commandだけが利用するため同じpackageに置いています。別commandやlibrary APIから
再利用する段階になったら、安定させたい境界を見極めたうえで internal packageへ移します。
Table Model
表形式は必ず1行目をヘッダーとして扱います。
type table struct {
Header []string
Rows [][]string
}
CSV/TSV/XLSXの読み込みでは、短い行を空文字で埋めて列数を揃えます。ヘッダーより 長い行は、名前のない値を破棄しないようエラーにします。 XLSXの書き出しではヘッダーを太字にし、1行目を固定します。
Flattening
structured -> table では、入れ子のmap/arrayを列パスへ展開します。
- map:
user.name - array:
items[0].sku - delimiterを含むmap key:
settings["build.target"] - top-level scalar:
value
列順は安定性を優先してソートしています。Excel上で列の位置が変わっても、 ヘッダー名を見て復元するため、列順には依存しません。
Unflattening
table -> structured では、ヘッダーのパス表現からmap/arrayを復元します。
例:
items[0].sku
は次の構造になります。
{
"items": [
{
"sku": "..."
}
]
}
セル値は parseCell で軽く型推定します。
- 空文字:
"" true/false: boolean- 整数: int64
- 小数または指数表記: float64
- その他: string
ゼロ埋め整数と前後に空白があるセルは、IDや文字列を壊さないためstringとして 保持します。複数列が同じパスで異なる中間型を要求する場合はエラーにし、入力列を 黙って捨てません。
Path grammar
現在の列パスは次の要素を扱います。
path = first-key, { map-child | quoted-key | array-index };
first-key = bare-key | quoted-key;
map-child = ".", bare-key;
quoted-key = "[", JSON-string, "]";
array-index = "[", digit, { digit }, "]";
実例は user.name、items[0].sku、orders[0].items[1].qty です。map keyに
.、[、] が含まれる場合や空文字の場合は、["build.target"] や [""] の
ようなJSON quoted keyを使います。連続したarray indexも扱うため、
matrix[0][1] を復元できます。入力サイズに対して過大なmemory allocationを
起こさないよう、pathは最大256要素、array indexは最大10000です。
Structured input integrity
- JSON inputはUTF-8として検証します。decoderは最初の値の後まで読み、空白以外の 後続データを拒否します。object keyもtoken単位で読み、重複を拒否します。
- YAML decoderはstream終端まで読み、複数文書を順序付きsliceとして保持します。
rows、records、itemswrapperはオブジェクト唯一のキーである場合だけ table rowsとして展開します。- recordが存在するのにscalar fieldが1つもないstructured valueは、表へ変換すると record数を失うため拒否します。空のrecord listは空の表として扱います。
TOML Output
TOMLはトップレベル配列を直接表せないため、表からTOMLへ出力する場合など、
トップレベルがmapでない値は rows キーに包んで出力します。
Dependencies
github.com/xuri/excelize/v2: XLSX読み書きgopkg.in/yaml.v3: YAML読み書きgithub.com/BurntSushi/toml: TOML読み書き
Go 1.25以上を前提にしています。
Error handling
- 未対応形式、decode失敗、workbook/sheet操作失敗は呼び出し元へerrorを返します。
- CSV/TSVのinvalid UTF-8、headerより長い行、値を持つ空header列を拒否します。
- path復元中の重複header、構文エラー、型競合は変換全体をerrorにします。
- XLSXのstyle・pane設定も通常の変換errorとして扱い、不完全なworkbookを成功扱いしません。