fo:page-sequence ページ番号の制御

非常に素朴と言うか基本的な話なのですが、fo:page-sequenceのページ番号の制御で以前ハマっている例を見たことがあります.fo:page-sequenceというのは、XSL-FOのfo:rootの下の中核的なオブジェクトで一連の同じ特徴を持ったページコンテンツの集まりです.同じ特徴というのは例えば

1. 同じヘッダーやフッターの形式をしている(fo:static-contents)
2. 同じ規則のレイアウトのマスターを選択する(fo:page-sequence/@master-reference)

というようなものです.よく技術文書をpublishするときに印刷用、WEB用という使い分けをします.印刷用だったら、左右ページは左右のマージンを変え、目次や章は必ず右ページ(奇数ページ)に出して、最後のページは例えば4の倍数で終わらせるなどという条件がよくあります.でもWEB用だと印刷でなく閲覧用なので左右ページのレイアウトは同じで、目次や章も必ずしも奇数ページからはじまることをしない条件になります.もっともこのように印刷用とWEB用を作り分けると、お客様から「何ページの~は?」問い合わせがあった場合と言った時に、印刷した本とWEB用のPDFでページ番号が同じになっていないと困るので印刷用をそのままWEB用のPDFに流用する場合もあります.(でも見づらい場合もありますね)

さて、ページ番号でやはり一番問題となるのは印刷用です.fo:page-sequenceでページ番号を制御するのは次の2つのプロパティです.

・ initial-page-number
・ force-page-count

initial-page-numberは文字通りそのfo:page-sequenceをなんのページ番号で開始するかの指定です.force-page-countはそのfo:page-sequenceのページ数にどのような制約を加えるかという指定です.このような指定は一回やってうまく動いてしまうとそのままで、あとで直すことはめったにないのでとかく仕様を忘れがちです.基本は、どちらも"auto"が一番ということです.あとはこれに「必要な変更」のみ加えてゆきます.

例えば、章のfo:page-sequenceを必ず右ページ(奇数ページ)から始める場合は、initial-page-number="auto-odd"だけで済みます.ここで妙に「ならば前のfo:page-sequenceのforce-page-countをいじくってはいけません.例えば、force-page-count="end-on-even"などとする人がいます.でもそんな必要はまったくないのです.何故かと言うとforcae-page-count="auto"は

7.27.6 "force-page-count"

auto
Force the last page in this page-sequence to be an odd-page if the initial-page-number of the next page-sequence is even. Force it to be an even-page if the initial-page-number of the next page-sequence is odd. If there is no next page-sequence or if the value of its initial-page-number is "auto" do not force any page.

ということでautoにしておきさえすれば、次のfo:page-sequenceのinitial-page-numberプロパティを見て自動的にページ数を調整(必要だったら空白ページを入れるなど)を自動的にやってくれます.

ここで勘違いして「じゃあforce-page-count="no-force"でも同じか?」と考えてこの値を指定することは危険です.Formatterは"no-force"だとなんのページ制御の面倒も見てくれなくなります.この結果左右ページの順序(偶数:左、奇数:右)がなんの警告もなく崩れます.まずこの値は使う必要はありません.

あとforce-page-countを使用する箇所はpublishingの最後のfo:page-sequenceです.印刷用の場合、複数のページをまとめて印刷して裁断とかいろいろな条件があるので、XSL 1.1で定義されている、

auto | even | odd | end-on-even | end-on-odd | no-force | inherit

という値では到底足りません.これにはFormatterの持っている拡張属性を使用します.XSL Formatterでは、以下のように非常にフレキシブルな指定ができます.まず印刷用途のほとんどすべての要件に対応できるでしょう.

force-page-count

問題は、「最後のfo:page-sequenceを何をもって判定するか?」です.こればかりは入力データに依存します.例えばDITAだったら必ずchapterかappendixで終わる条件なら簡単に判別できるでしょう.でもbackmatterが入ってくると話はややこしくなります.backmatterは非常に自由度が高いからです.例えばbackmatter/booklists/indexlistの索引で必ず終わるというような条件をお客様からいただければ大変助かります.

ハマった例は、force-page-countだけでなく、左右ページ毎にレイアウトを変えているため、なかなかバグが入力データに依存して、見つかりづらいというものでした.例えば、章のfo:page-sequenceを奇数ページから始める場合、前のfo:page-sequenceのforce-page-count="auto"であっても、偶数ページの空白ページに対応したページマスターが必須です.またpublishingの最終ページを4の倍数で終わらせようとすれば、そのfo:page-sequenceが参照する(master-reference)ページマスターには、間違いなく左右の空白ページのページマスター定義が必要になります.

という訳でやはり印刷用というのは今も昔も難しいことに変わりはないと思います.要は必要なページマスターをちゃんと定義して、initial-page-numberとforce-page-countは"auto"から必要な箇所のみ変更を加えるということが基本だと思います.