複雑な構造を持つExcelレポート(例えば、週単位、日単位、サービス単位でネストされたデータや、バージョンごとに分かれたシートなど)をプログラムで一から構築するのは、コードの可読性とメンテナンス性の観点から非常に困難です。このような場合、MustacheやHandlebars形式のプレースホルダを埋め込んだExcelファイルをテンプレートとして用意し、そこにデータを流し込む手法が効率的です。
テンプレートベースの生成アプローチ
Go言語において、テンプレートを用いたExcel操作を実現するために github.com/ivahaev/go-xlsx-templater というライブラリが有効です。このライブラリは、内部的にExcel操作用の tealeg/xlsx と、テンプレートエンジンの aymerick/raymond を組み合わせて動作します。
基本的なワークフローは以下の通りです。
import (
"github.com/ivahaev/go-xlsx-templater"
)
func generateBasicReport() {
// テンプレートの初期化
report := xlst.New()
err := report.ReadTemplate("./template.xlsx")
if err != nil {
panic(err)
}
// データの注入
dataContext := map[string]interface{}{
"Title": "月次業務報告書",
"Items": []map[string]string{
{"Name": "サーバー保守", "Status": "完了"},
{"Name": "バックアップ確認", "Status": "進行中"},
},
}
// レンダリングと保存
report.Render(dataContext)
report.Save("./output.xlsx")
}
複数シートの一括生成への拡張
標準的な機能では、テンプレート内のシートを個別に処理することは可能ですが、一つのデータ集合から動的に複数のシートを生成する場合にはカスタマイズが必要です。以下は、スライス形式のパラメータを受け取り、それぞれのデータに対して新しいシートを割り当ててレンダリングする拡張実装の例です。
type ReportConfig struct {
SheetTitle string
Data interface{}
}
func (x *Xlst) ExportMultiSheetData(configs []ReportConfig, opts *Options) (*xlsx.File, error) {
if opts == nil {
opts = &Options{}
}
newFile := xlsx.NewFile()
// テンプレートの最初のシートをベースに使用
baseSheet := x.file.Sheets[0]
for _, cfg := range configs {
// 新規シートの作成
targetSheet, err := newFile.AddSheet(cfg.SheetTitle)
if err != nil {
return nil, err
}
// シート構造のコピー
replicateSheetStructure(baseSheet, targetSheet)
// テンプレートエンジンのコンテキストにデータをバインド
renderErr := processRows(targetSheet, baseSheet.Rows, cfg.Data, opts)
if renderErr != nil {
return nil, renderErr
}
// カラム設定の同期
targetSheet.Cols = append(targetSheet.Cols, baseSheet.Cols...)
}
return newFile, nil
}
印刷設定とレイアウトの最適化
実用的なレポートでは、セルの折り返し設定による行高さの自動調整や、印刷時の改ページ挿入といった細かい制御が求められます。特に tealeg/xlsx を使用する場合、改ページ(Page Breaks)情報を保持するために構造体を拡張し、XML定義にマッピングする必要があります。
// xlsxライブラリのSheet構造体に改ページ情報を追加する定義
type CustomSheet struct {
Name string
Rows []*Row
Cols []*Col
// 印刷制御用の改ページフィールド
RowPageBreaks *XlsxBreaks `xml:"rowBreaks"`
ColPageBreaks *XlsxBreaks `xml:"colBreaks"`
}
type XlsxBreaks struct {
Count int `xml:"count,attr"`
Manual int `xml:"manualCount,attr"`
Brk []XlsxBreak `xml:"brk"`
}
type XlsxBreak struct {
ID int `xml:"id,attr"`
Max int `xml:"max,attr"`
Man bool `xml:"man,attr"`
}
このように、既存のライブラリが提供する機能が不足している場合は、基礎となるデータ構造(XMLマッピング層)に手を入れることで、Excel固有の高度な機能(改ページプレビューやオートフィルター設定など)をGoから操作できるようになります。テンプレート方式は、デザインとロジックを分離できるため、複雑な要件のビジネスレポート作成において非常に強力な武器となります。