Files
dataxl/docs/architecture.md
Luno 2e96d174f2
All checks were successful
CI / test (pull_request) Successful in 26s
Document conversion internals and limits
2026-07-18 16:25:50 +09:00

120 lines
3.6 KiB
Markdown

# 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 adapter
- `table.go`: CSV/TSV/XLSX adapter、table model、flatten
- `path.go`: セル値の型推定、列パスのparse、unflatten
`convert` はファイル入出力から独立しているため、CLIを経由せず変換matrixをテストできます。
形式固有処理は `parseStructured` / `encodeStructured` または
`parseTable` / `encodeTable` に閉じ込めます。
現状は単一commandだけが利用するため同じpackageに置いています。別commandやlibrary APIから
再利用する段階になったら、安定させたい境界を見極めたうえで `internal` packageへ移します。
## Table Model
表形式は必ず1行目をヘッダーとして扱います。
```go
type table struct {
Header []string
Rows [][]string
}
```
CSV/TSV/XLSXの読み込みでは、短い行を空文字で埋めて列数を揃えます。
XLSXの書き出しではヘッダーを太字にし、1行目を固定します。
## Flattening
structured -> table では、入れ子のmap/arrayを列パスへ展開します。
- map: `user.name`
- array: `items[0].sku`
- top-level scalar: `value`
列順は安定性を優先してソートしています。Excel上で列の位置が変わっても、
ヘッダー名を見て復元するため、列順には依存しません。
## Unflattening
table -> structured では、ヘッダーのパス表現からmap/arrayを復元します。
例:
```text
items[0].sku
```
は次の構造になります。
```json
{
"items": [
{
"sku": "..."
}
]
}
```
セル値は `parseCell` で軽く型推定します。
- 空文字: `""`
- `true` / `false`: boolean
- 整数: int64
- 小数または指数表記: float64
- その他: string
ゼロ埋め整数は、IDやコードを壊さないためstringとして保持します。複数列が同じパスで
異なる中間型を要求する場合は、先に構築された値を後続列で上書きしません。
### Path grammar
現在の列パスは次の要素を扱います。
```text
path = key, { ".", key | "[", index, "]" };
index = digit, { digit };
```
実例は `user.name``items[0].sku``orders[0].items[1].qty` です。
区切り文字を含むmap keyのescapeは未対応です。
## 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.24以上を前提にしています。
## Error handling
- 未対応形式、decode失敗、workbook/sheet操作失敗は呼び出し元へerrorを返します。
- path復元中の型競合は既存値を保護するため、その列の適用を中止します。
- XLSXのstyle・pane設定も通常の変換errorとして扱い、不完全なworkbookを成功扱いしません。