文書構造

いくつかの小説ホスティングサイトから文書を取得して電子書籍 (ePub 形式) を生成するスクリプトを私は以前に作って公開している。

SaitoAtsushi/yomou-publisher at ff3950e

いくつかのサイトに対応していることもあって ePub 生成する部分をひとつのライブラリとしてくくり出しているのだけれど、ひどいインターフェイスでとても汎用的には使えない。 問題のひとつは文章構造の表現のしかただ。

文書と文章構造はリストにまとめて渡すようになっている。 例で言えばおおよそ以下のような形式だ。

("第1章"
 ("001.xhtml" "第1章 第1話 ほにゃらら" "ほにゃらら本文")
 ("002.xhtml" "第1章 第2話 かくかく" "かくかく本文")
 ("003.xhtml" "第1章 第3話 しかじか" "しかじか本文")
 "第2章"
 ("004.xhtml" "第2章 第1話 なんたら" "なんたら本文")
 ("005.xhtml" "第2章 第2話 かんたら" "なんたら本文"))

リストの要素は

  • 章の名前
  • 各話のファイル名と表題と本文をリストでまとめたもの

のいずれかである。

しかしこのような表現では行き詰まりが出てきた。 文章のまとめをネストできないからである。 例えば「第何部」「第何章」「第何節」というようにいくつかの話をまとめてそれを更にまとめるというような構造が表現できないのである。 主要な小説ホスティングサイトではネストする機能がなかったこともあって想定しなかったわけだが、 KADOKAWA が始めたカクヨムというサービスではネストできるようで、実際にそうしている作品もある。 ライブラリとして汎用的にするなら想定して然るべきであった。

単純に考えれば、リストに入れるのだから適当にグループ化すればいいじゃないかと思うだろう。 こんな要領で。

(("001.xhtml" "まえがき" "まえがき本文")
 (section "第1部 導入編"
   ("002.xhtml" "プロローグ" "プロローグ本文")
   (section "第1章"
     ("003.xhtml" "第1章 第1話 最初の話" "ほにゃらら")
     ("004.xhtml" "第1章 第2話 次の話" "ほげほげ")
     ("003.xhtml" "第1章 第3話 一段落" "ふがふが"))
   (section "第2章"
     ("004.xhtml" "第2章 第1話 次の事件" "わはー")
     ("005.xhtml" "第2章 第2話 解決" "むすー")))
 (section "第2部 発展編"
   (section "第3章"
     ("006.xhtml" "第3章 第1話 開始" "かくかく")
     ("007.xhtml" "第3章 第2話 開始" "しかじか")))
 ("008.xhtml" "あとがき" "あとがき本文"))

これならいくらでもネストできる。

とは言っても、そもそも論として文章構造と文章の内容をひとつのリストにまとめるのは妥当だろうか。

各話ごとに書き出してしまえばメモリ上で全体を保持する必要はなく、効率は良くなる。 目次などのメタデータだけは最後に整理して出力すればよい。 これは見掛け上、オブジェクトに対するメッセージとしてインターフェイスを整理できる。

しかし、メッセージは時系列での順序しかない。 ネストをどう表現するかを考えると、グループの開始と終わりを表すメッセージを投げる方法が考えられる。 上の例をメッセージで表すならこうなる。

(let ((book (book-open "ファイル名.epub" "表題" "作者" "概要")))
  (add-html book "001.xhtml" "まえがき" "まえがき本文")
  (start-section "第1部 導入編")
  (add-html book "002.xhtml" "プロローグ" "プロローグ本文")
  (start-section "第1章")
  (add-html "003.xhtml" "第1章 第1話 最初の話" "ほにゃらら")
  (add-html "004.xhtml" "第1章 第2話 次の話" "ほげほげ")
  (add-html "003.xhtml" "第1章 第3話 一段落" "ふがふが")
  (end-section)
  (start-section "第2章")
  (add-html "004.xhtml" "第2章 第1話 次の事件" "わはー")
  (add-html "005.xhtml" "第2章 第2話 解決" "むすー")
  (end-section)
  (end-section)
  (start-section "第2部 発展編")
  (start-section "第3章")
  (add-html "006.xhtml" "第3章 第1話 開始" "かくかく")
  (add-html "007.xhtml" "第3章 第2話 開始" "しかじか")
  (end-section)
  (end-section)
  (add-html "008.xhtml" "あとがき" "あとがき本文")
  (book-close book))

書籍となるとカスタマイズしたい事項は無数に生じる。 縦書き/横書きだとかスタイルシートの指定だとか、そういったものをオプションとして手続きに渡すとなると引数の数が際限なく増えて不格好になるのでそういったオプション要素もオブジェクトに対してメッセージで投げられるようにすれば一貫したインターフェイスに出来るだろう。

この方向でスクリプトを整理しなおすことを考えている。

Document ID: 3067cd99051d86bf097ce5c87f68c459