黄昏の迷宮

知的好奇心を刺激する冒険

ExcelワークシートをJSONに変換する

AstroやSvelteなどでサイトを作る際にデータをFetchして表示することが多いと思いますが、サイト制作でちょっとした共通データ(例:SELECTリスト用)を扱う際APIを用意するのも手間ですよね。そこで、ExcelのワークシートをJSONに変換して使うことにしました。

使い方

まずはリポジトリからソースを取得してビルドします。

🔗hyperdb/xlsx2json

次に設定用のJSONファイルに以下のようにパラメーターを記述します。

{
    "xlsx_dir" : "(Excelワークブックのディレクトリ名)",
    "xlsx_wb"  : "(ワークブック名)",
    "xlsx_ws"  : "(ワークシート名)",
    "dist_dir" : "(JSON出力先のディレクトリ名)"
}

そしてソースからビルドしたコマンドを実行します。

xlsx2json -s (設定ファイルのパス)

例:

xlsx2json -s ./config.json

これで指定したワークシートの内容がJSON形式で出力されます。出力先のディレクトリには、ワークシート名を元にしたJSONファイルが生成されます。たとえば、config.jsonで指定したワークシート名がdataの場合、data.jsonというファイルが出力されます。

出力されたJSONをAstroのコンポーネントでImportして使うことができます。

import json from '@data/data.json';

なお、SvelteKitなどで使う場合はFetchしてからコンポーネントに渡す必要があります。

🔗Svelte 入門: JSON ファイルをインポートして使う|まくろぐ

ひとりごと

最初はPHPAPIサーバーらしきものを作ってFETCHして使おうと思っていたのですが、APIサーバーを立てるのも面倒だなと思い、ExcelのワークシートをJSONに変換して使うことにしました。個人で使う分にはこれで十分です。

思い立ったら

このブログの記事を書くにあたり、どうせならVS Codeで書こうと思ってはてなブログAtomPubを使ってみることにしました。

下書きディレクトリに作ったマークダウンファイルに記事を書いて、書き終わったらAPIで投稿するイメージです。

以下のツールを使わせていただいております。 x-motemen/blogsync: Push and pull blog entries from/to local filesystem

環境ができればどんどん書いていけばいいのですが、下書きのファイルの名称をどうしようかという部分で引っ掛かってしまいました。 そんなものは下書きなんだから「1.md」とかでいいじゃないかとも思うのですが、思い立ったら何かしないと気が済まない方なので自動で名前を生成して空のファイルを作成するスクリプトを作りました。

仕様は至って単純、実行時点のUNIX時間を62進数に変換してファイル名にして指定したディレクトリに作成するものです。マークダウンだったりテキストだったりするかもしれないので拡張子も指定するようにしました。

などと言っていますが、大枠はGeminiが作っています。

package main

import (
 "fmt"
 "os"
 "path/filepath"
 "strings"
 "time"
)

const base62Chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

// int64をbase62文字列に変換する関数
func toBase62(num int64) string {
 if num == 0 {
  return string(base62Chars[0])
 }

 var result strings.Builder
 base := int64(len(base62Chars))

 for num > 0 {
  remainder := num % base
  result.WriteByte(base62Chars[remainder]) // 文字を追加
  num /= base
 }

 // 結果は逆順になっているため、元に戻す
 runes := []rune(result.String())
 for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
  runes[i], runes[j] = runes[j], runes[i]
 }
 return string(runes)
}

func main() {
 // 1. コマンドライン引数を確認
 if len(os.Args) != 3 {
  // os.Args[0] はプログラム名なので、引数は2つ必要
  fmt.Fprintf(os.Stderr, "使用法: %s [file extension] [dist directory]\n", filepath.Base(os.Args[0]))
  fmt.Fprintf(os.Stderr, "例: %s txt ./output\n", filepath.Base(os.Args[0]))
  os.Exit(1)
 }

 fileExt := os.Args[1]
 distDir := os.Args[2]

 // 拡張子の先頭にドットが付いている場合は削除 (例: ".txt" -> "txt")
 if strings.HasPrefix(fileExt, ".") {
  fileExt = fileExt[1:]
 }

 // 拡張子が空の場合はエラー
 if fileExt == "" {
  fmt.Fprintln(os.Stderr, "エラー: ファイル拡張子は空にできません。")
  os.Exit(1)
 }

 // 2. 現在のUNIX時間を取得
 unixTime := time.Now().Unix()

 // 3. UNIX時間をbase62に変換
 base62Name := toBase62(unixTime)

 // 4. ファイル名とパスを構築
 fileNameWithExt := fmt.Sprintf("%s.%s", base62Name, fileExt)
 fullPath := filepath.Join(distDir, fileNameWithExt)

 // 5. distディレクトリが存在しない場合は作成
 //    os.MkdirAll は親ディレクトリも必要に応じて作成し、ディレクトリが既に存在してもエラーにならない
 err := os.MkdirAll(distDir, 0755) // 0755: rwxr-xr-x
 if err != nil {
  fmt.Fprintf(os.Stderr, "エラー: ディレクトリ %s の作成に失敗しました: %v\n", distDir, err)
  os.Exit(1)
 }

 // 6. 空のファイルを作成
 file, err := os.Create(fullPath)
 if err != nil {
  fmt.Fprintf(os.Stderr, "エラー: ファイル %s の作成に失敗しました: %v\n", fullPath, err)
  os.Exit(1)
 }
 file.Close() // ファイルを作成するだけなので、すぐに閉じる

 fmt.Printf("ファイルが正常に作成されました: %s\n", fullPath)
}

このファイルをビルドしてEXE化した後、PATHの通った場所に移せば準備は完了です。 実行ファイル名を「base62file.exe」とすると以下のような感じで空のファイルを作ることができます。

base62file md ./drafts

まあ、正直無くても困らないものではありますが、思い立ったらとりあえず作ってみるのは正直楽しいものです。

6月に入りました

6月に入りました。

自分の勤務する会社は期首が6月なのでまさに新年度に入ったところです。あと1年ちょっとで定年を迎える身としてはいろいろ思うところはあったのですが、いざその時が間近に見えてきても多少気持ちがモヤモヤするだけで、とくに何かをすぐにしなければならないという雰囲気にはなりません。まあ、人間案外そんなものかもしれませんね。

とはいえ何もしなくてもその日はやってくるわけで、引き継ぎだったりその後のことを考えた動きをいろいろとやらなければならないので、そんなときにモヤッとしたことを中心にブログとして書いていこうと思います。

その日まであと393日。 果たしてどのくらい記事が書けるのか、自分でも楽しみにしています。