タグ別アーカイブ: XSL-FO

『Office Open XML Formats入門 第2版』を制作しました

2021年12月07日 16:00~17:00 に「ちょっと一息アンテナハウスウェビナー『Office Open XML Formats入門 第2版』制作報告」を発表しました。販売、公開よりも発表が先になってしまったため、内容が気になっていた方もいらっしゃるのではないでしょうか。

こちらが表紙画像です。

Amazon POD用表紙画像

2021年12月07日ウェビナーのバナー

組版をAH XSL Formatter V7.2で行ったため、『AH Formatter XML関連出版物の紹介』ページに掲載しています。

Amazonの販売ページへのリンクは次の通りです。

https://www.amazon.co.jp/gp/product/4900552836

また、本書のPDF版は弊社オンラインショップからご購入いただけます。印刷版とレイアウトの微調整を行いました。

https://web.antenna.co.jp/shop/html/products/detail.php?product_id=1301

HTML版はOffice Servers資料室のページからご覧いただけます。


ウェビナー概要や書籍紹介ページにある通り、アンテナハウス『Office Open XML Formats入門』の初版は2007年に出版社から刊行されました。
今年は2021年、つまり14年程前の書籍の改訂版ということになります。
内容的な修正は必要とはいえ、以前の版の原稿をベースに新たな版を制作するというとき、XML原稿はほとんど変更が必要ありません。以前の版の構造に不満がある場合はその限りではありませんが。

一方で大規模な修正の余地があるのがXSLTでした。そしてウェビナー(と書籍の後書き)では、XSLTについてはかなり省いて説明することになったため、本記事ともう一度どこかで補足することにしたいと思います。

2007年というのは、XSL的にもそこそこ大きな節目でした。XSLT 2.0のW3C勧告です。XSL 1.1の勧告は2006年でしたが、実利用として熟れていないという点では二者とも同様です。XSLT 2.0以降はミスの発見やスクリプトの見通しにおいてXSLT 1.0とは別言語に近い体験をもたらします。msxmlのXSLTが1.0であることや各ウェブブラウザほか処理系の多くが1.0までしか対応していないことも手伝って、使える状況が限られるのは悩ましいところです。

変更の概略

今回は自社事例でしたので、初版で1.0だったXSLTを3.0に書き換えました(完全に3.0向けに最適化したとはとても言えませんが)。

書籍初版の制作報告にもあったように、XSL 1.1での大きなポイントにbookmarkのとindex関係の語彙が入ったことが挙げられます。『Office Open XML Formats入門』初版では、bookmarkについてはXSL Formatterの拡張仕様、索引についてはbasic-linkとXSLTによる力技による解決が図られていました。

(AH )XSL Formatterの拡張仕様では実際のフローコンテンツ登場箇所と同一の箇所に記述するため、処理においてXML中の章構造に当たったときに同時に処理すれば良いことになります。よってXSLT記述としてはbookmark-tree用に処理を追加するよりも単純に書けます。XSLT 1.0で書く場合は複数回ドキュメントを走査することが難しいということも手伝っていたのかもしれません。

索引構造については、XSL 1.1のindexを導入することで、XSLTで行わなければならなかった処理が簡略化されます。索引語に当たったときの処理で、「既に同じ索引語が登場しているか」「同じ索引語が同ページに登場したときにページ数表示を合一する」といった判別がXSLのプロパティで変更可能になるため、分岐処理などが大幅に簡略化できました。

割とアドホックな書き換えを行っていたり、徹底できていなかったりするため、引き継ぎをするにはリファクタリングが必至ですが、大体このようなことを行いました。

  • テンプレート中に直接書き込まれたattributeをattribute-setへまとめる
  • 共通処理をまとめる。
  • apply-templatesを含まないような分岐は名前付きテンプレートへ追いだし、パラメータを渡すようにする
  • XPathによる値の取得はできるだけテンプレートの先頭でまとめ、利用箇所ではselect="$value"のように呼び出すだけにする

先に書いた通り徹底はできておらず、私自身も、テンプレート中で直接attributeを指定しているような箇所をかなり生み出してしまいました。とはいえ、ギリギリの時期に「ヘッダーの位置をもう少し下げて」といった指示に1行の変更だけで対応できるようにはできたので、無駄ではなかったと思います。

実は上に挙げたものはXSLT 1.0時点でも時間さえあれば行える変更で、3.0への変更には関係ありません。値のみを取得、操作したい箇所をfunction化したり、処理をreplace()関数に書き換えたりといった作業は2.0から行えます。3.0としては関数の括弧が入れ子ではなくarrowを使えたり、文字列結合に「||」を使えるといった枝葉の変更点を使用しています。

参考資料




瞬簡PDF 作成 2024
ドラッグ&ドロップでPDF作成


HTML on Word
WebページをWordで作る!

XSL-FO 試行錯誤 カレンダーを自動生成したい(構想編)

師走まで間もなくとなり、日中の気温もかなり下がってきました。来年のカレンダーを用意する時期ですね。
ちょっと「XSL-FOでオリジナルのカレンダーを作りたい」なんてこともあるのではないでしょうか。

高々12月分であるのでDTPソフトウェアやXSL-FOの直書きで頑張っても何とかなるかもしれませんが、来年もある程度使い回せるようにしたり、2021年のように直前の変更があるかもしれないことを考えると自動化したいところです。

実現したいカレンダーは次のようなものを想定します。手書きであるため半端なところまでしか日付がありません。

実現したいカレンダーのラフ

今回は構想編ということで、方針や使っていくFO、XSLTのアタリを付けていきましょう。

ページレイアウト

カレンダーを作るにあたって、先ず決めなければいけないことは「どの程度グラフィカルにするか」、具体的にはページレイアウトをどこまで制限するか、ということです。
個別箇所の自由度を上げるとその分だけ自動化できる箇所は少なくなります。

とはいっても、「高々12月分」と書いたように12パターン程度であれば12通りのページレイアウトを用意しても良いでしょう。今回はページレイアウトを1つに定めることにします。

  • ページレイアウトは1つ
  • 毎月1ページで構成

(スケジュール帳を組むのであれば「1月分の中にページ分割はあるか」も考慮しなければなりません。AH XSL Formatterであれば見開き要素が使えるため比較的簡単に対応できます。その場合は、見開きの左右に分割される位置と格子の位置を上手く配置する工夫が必要になりますね。)

ページサイズはA3縦(縦420mm、横297mm)にしましょう。

毎ページ登場する内容

月ごとにページを分けるのであれば、各ページに共通して登場するのは
年でしょうか。来年であれば「2022年」ですね。これはstatic-contentに置くことにします。
また、年度(4月始まり)で設定したい場合、途中で年の表示は変わりますね。このことに備えて、マーカーで取り出した値を使うことにします。

後述するように画像を上半分にページ幅一杯に表示する際、画像の上にstatic-contentを被せて表示することが可能です。AH XSL Formatterではregion表示の優先順位も自由が利きます。

マス目表示を実現するFO

ここは奇をてらわずtableを使っていきます。

カレンダーでは、曜日をカラムのタイトルとして、1週目、2週目、…をrowのまとまりとして、それぞれの日付がセルとして表されます。
常にマス全体を長方形にすることとして、rowの数は5週分にします。

例示した画像のように日付の始まりと曜日の始まりが一致するなら並べるだけなので楽ですが、そうではないためXSLTで自動化することになります。当月の他、その先月または来月の数日間の情報が必要になることも、お手元のカレンダーから想像が付くのではないでしょうか。

元となるカレンダー用のXMLがある場合は、そこにテンプレートを適用するだけで済むでしょう。

日付の位置を調整して自動生成するXSLT

XSLT 2.0からは日付のための関数や型を利用できます。ある日付の曜日を取りたいときはたとえばformat-date('[w1]')とすればxs:integer型ではありますが曜日が取得できます。このことと日付用のduration、そしてmodを組み合わせればカレンダーのマス目が実現できそうです。

休日・祝日(今回は対応しない)

休日、祝日の背景色を変更することについて考えます。日曜を示すカラムが先に決まるため「毎週日曜の背景色を変更する」であればカラムに対して設定したりすれば良いでしょう。問題は祝日です。XSLTの標準ライブラリは日本の祝日対応まではしてくれていません。確実なソースとなると、内閣府のページにあるCSVでしょうか。

「国民の祝日」について – 内閣府

XSLT 2.0以降でCSVをパース可能なようにプログラムを書くこともできますが(<xsl:analyze-string>などを使います)、とりあえず今回は対応しないことにします。

そのほか二十四節気なども同様に、「どこかから日付と紐付いた外部ソースを得る」「XSLTで取り込んで展開する」といった手順になるでしょう。

各月のイラスト、写真の設定方法

話をFOメインに戻します。

ページレイアウトは1つだけにすることを決めました。
AH XSL Formatterではページマスターに背景画像を設定することも可能ですが、
1つのページレイアウトを使い回すのであれば、フローコンテンツとして指定していく形になるでしょう(実はマーカーに画像を指定することも可能ですが、テンプレートの記述量は大して変わりません)。

画像のクリッピングや位置調整については背景画像の方がプロパティ指定の余地が広いため、ブロックコンテナーの背景画像として配置することにします。

画像をページギリギリまで表示したい場合、フローコンテンツを塗り足し領域まで表示させる必要があります。この辺りのTipsは『AH XSL Formatter 拡張仕様使いこなしガイド』に載せていたりします。

次回予告

次回はカレンダーを実現するための関数、テンプレートについて考えていく予定です。

参考資料





HTML on Word
WebページをWordで作る!


瞬簡PDF 統合版 2024
アンテナハウスPDFソフトの統合製品!

【動画公開】「DITAで本を書いてAH XSL Formatterで自動組版する」、FormatterClub2021ウェビナーのお知らせ

2021年8月10日に開催しました、ちょっと一息アンテナハウスウェビナー「DITAで本を書いてAH XSL Formatterで自動組版する」の録画を編集した動画が公開されています。

動画は1本10分程度の4本立てとなりました。

ご好評いただけましたようで、当日は予定時間をはみ出すくらいにご質問をいただきました。
「タグを気にせず書きたい」といった意見もございました。個人的には「タグを気にしながら書きたい」派でしたのでそういった方のための資料はあまり用意できていなかったのですが、そういった方面のアプローチも存在しますので、機会があればあらためてまとめたいと思います。

さて、この動画自体は少し前に公開されたのですが、何故今ブログ記事にしているかというと、次のイベントに関連するためです。

FormatterClub2021ウェビナー開催

日時
2021年9月17日(金)17:00~18:10
概要
今回のFormatterClubでは、キヤノンの吉田一様にFormatterでのマニュアル作成と自動組版の取り組みの発表の他、XSL拡張仕様のご説明、AH Formatterの今後をご紹介を致します。
内容紹介・お申込みページ
ウェビナー登録ページ【終了しました】

Formatter Club は、アンテナハウスの XML 自動組版ソフト『AH Formatter』を導入されているユーザーや関心を持っていただいている皆様と開発者とを繋ぎ、会員同士の交流、情報交換により『AH Formatter』の利用技術を向上させ、より皆様のお役に立てる製品としていくために役立てることを目的として発足いたしました。
『AH Formatter』とその関連技術(XSL、CSS、XML 多言語組版など)に関心のある方でしたらどなたも参加できます。参加費は無料です。
Formatter Club の活動には会員メーリングリストを情報交換のために利用し、会員専用の Web ページも提供いたします。また定例会を開催し、会員相互の親睦をはかります。定例会は、『AH Formatter』開発者から最新バージョンの紹介・デモ、活用事例紹介、組版技術の向上のための勉強会などを行います。

Formatter Club について | アンテナハウス株式会社

ということで、「XSL拡張仕様のご説明」として『使いこなしガイド』の紹介をさせていただく予定です。
今回のウェビナーはFormatter Club会員様以外でも参加が可能ですのでお気軽にご登録、ご視聴ください。

関連記事





瞬簡PDF 作成 2024
ドラッグ&ドロップでPDF作成


瞬簡PDF 書けまっせ 2024
PDFに文字が書ける! 入力欄を自動認識

XSL-FO試行錯誤 索引の索引関連FO以外の箇所

個人的な話として、索引周りは既にあるなら自前で実装したくはない箇所です。

索引に関連した仕様はXSL-FO 1.1で追加されました*1。1.1は2007年には登場しており、私が学び始めた時点で既に存在します。

先日それ以前に書かれたコードに触れる機会があり、<fo:basic-link>とXSLT 1.0で書かれた処理を見て苦労を偲びました。

索引関連のFOはアンカーと、アンカーの参照、その参照をまとめて書式などを調整するものがあります。

組版するまで未決定なページ番号関連の挙動を制御してくれる索引のFOですが、逆に、索引対象語のソートなどはXSLTなどで、索引の表示レイアウトは通常のブロックやリーダなどで行うことになります。

テキストの揃えやリーダ関係ではAH Formatterのマニュアルにあるように*2指定すれば、よく目にする「テキストはstartの端、ページ参照はendの端」という見た目の索引とできるでしょう。目次もこのようなレイアウトを取ることがあります。

索引の索引語ごとのブロックとしては@text-align@text-align-last、(axf:text-align-first)で揃えを制御し、@keep-together.within-pageでページ参照部分だけ次ページに分割されてしまうことがないように、という指定を行うことになるでしょうか。このときインラインの構造としては「索引語」「リーダ」「索引参照のFO」という並びになります。

さらに大きい構造として、「索引の見出し文字」と「索引語ごとのブロックの連続」となります。このとき見出し文字のブロックに@keep-next.within-pageでこの箇所での分割を避けておく必要がありますね。

参考資料





瞬簡PDF 書けまっせ 2024
PDFに文字が書ける! 入力欄を自動認識


HTML on Word
WebページをWordで作る!

XSL-FO試行錯誤 リストアイテムのインデントが効いていない?

改まった内容の記事は結構時間がかかりますが、このブログ連載のタイトルが「試行錯誤」なので、凡ミスを載せたりしても良いかな、ということで。
実際に起こった失敗より、一部改変しています。

XSLTで箇条書きにする変換を書いていたときのこと。

FOに変換後、PDF出力すると一部のリストブロックだけ箇条書きのラベルの上に箇条書きの内容が。
これ自体はインデントの指定を間違ったときにすぐ起こるので、あまり悩むことはありません。どこかでアイテムラベルかアイテムボディのインデント指定を上書きしてしまったのでしょう。

しかし、アイテムラベルやアイテムボディの周辺を見回しても特に不味いところは見当りません。仕様を把握している方は「ああ、それは多分……」とこの時点で見当がついたかもしれません。

それでは次のようなコードで、どんなことが起こり得るでしょうか?

<xsl:attribute-set name="atsList">
  <xsl:attribute name="provisional-distance-between-starts">ホニャララ</xsl:attribute>
  <xsl:attribute name="provisional-distance-label-separation">フガフガ</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="atsListLabel">
  <xsl:attribute name="start-indent">いいかんじ</xsl:attribute>
  <xsl:attribute name="end-indent">label-end()</xsl:attribute>
</xsl:attribute-set>

<xsl:attribute-set name="atsListBody">
  <xsl:attribute name="start-indent">body-start()</xsl:attribute>
  <xsl:attribute name="end-indent">ほどほど</xsl:attribute>
</xsl:attribute-set>


<xsl:template ...>
  <fo:list-block xsl:use-attribute-sets="atsList">
    <fo:list-item>
      <fo:list-item-label
       xsl:use-attribute-sets="atsListLabel">
        <fo:block xsl:use-attribute-sets="atsListLabelBlock">
          LABEL
        </fo:block>
      </fo:list-item-label>
      <fo:list-item-body xsl:use-attribute-sets="atsListBody">
        <xsl:apply-templates select="ナンチャラ"/>
      </fo:list-item-body>
    </fo:list-item>
  </fo:list-block>
</xsl:template>

答え合わせにいきましょう。

<!-- 変換後のFO -->
      <fo:list-item-body start-indent="body-start()" ... > 
        <fo:block start-indent="0pt" >
        ...
        </fo:block>
      </fo:list-item-body> 

実際に問題の指定があったのはこの箇所ではなく<xsl:apply-templates>の先、アイテムボディの内容を記述するブロックでした。start-indent="0pt"の指定があるブロックへ変換していた箇所があったのです。XSLTでattribute-setを分けていたため、気づくのが遅れました。それでも変換結果のFOを確認しながら作業していればもっと早くに気づけたのではないかと思います。

設計するときは、小さなテストケースや検証環境をあらかじめ用意しましょう。ホントに。




瞬簡PDF 統合版 2024
アンテナハウスPDFソフトの統合製品!


瞬簡PDF 変換 2024
PDFをOffice文書へ高精度変換

XSL-FO試行錯誤 XSL-FOにおけるテーブルレイアウトの利点

かつて多くのWebサイトでは、table要素を表組ではなくレイアウトのために用いる「テーブルレイアウト」が多く見られました。
これはテーブルをグリッドのように使うもので、rowspanやcolspanを組み合わせ、比較的簡単に(そして恐ろしく複雑な)Webページを作成できました。
衰退していった理由は非推奨であること*1やCSSで求めるレイアウトが可能になったこと、アクセシビリティへの関心の高まりなどさまざまにありそうですが、その中には「テーブル構造では異なる画面サイズに最適化した表示調整が困難」という理由もあるのではなかろうかと個人的には考えています。

つまり、出力時一時的に変換される、固定レイアウトを前提としたXSL-FOではいまだそれなりに有用ということです。
とはいえ、それこそHTMLにおけるテーブルレイアウトのようにグリッドの代用として使うのは最終手段にしたいところで、XSL-FOにおけるテーブルレイアウトの利点は他にあります。

static-contentとretrieve

さて、<fo:retrieve-marker>という名前のFOがあります。これを活用しstatic-contentでflow中に記述されたマーカから要素を引っぱることが可能です。static-contentはヘッダやフッタに用いられます。

任意のマーカからflowの任意の場所で要素を引っぱって来れれば可能な表現も増えるのですが、それはできません*2

flow中でヘッダ・フッタを持てるFO

ところで、flow中でヘッダ・フッタを持てるFOがあります。はい、<fo:table>です。しかもページ分割のときヘッダフッタの表示是非も指定可能なのです*3。ちなみにAH XSL Formatterでは段分割でomitするかどうかを制御可能です*4
そしてこの<fo:table-header><fo:table-footer>中では<fo:retrieve-table-marker>によってマーカから要素を引っ張れます。

そして、<fo:table-cell>にはブロックレベルのFOが格納可能です。この意味するところがおわかりになりますでしょうか。

あるセルの中のブロックがページ分割されるとき、当然(例外もあるかもしれませんが)セルもページ分割されます。ヘッダやフッタにretrieveのFOを置くことにより、マーカで中身を更新できますから、次のような表現だって可能になります。

分割後に「……continued」をヘッダ部に表示

テーブル唯一のセル中にブロックコンテナを置き、ブロックコンテナが分割されるときに「……continued」と表示されるようになりました。

<fo:table>以外のブロックでも分割前後に表示を変更可能なFOが仕様としてあることが個人的には望ましいですが、(XSL-FOにおける)テーブルレイアウトは、簡易的なflow内static-contentとして有用なのです。

ちなみに、「ヘッダやフッタではbeforeやafterにしか表示できずブロックのstartやend側の端に何かを表示できないのでは」という懸念は、限定的に解消可能です。ブロックコンテナには絶対配置というものがありましたね。(ただし、絶対配置のブロックコンテナは、他のオブジェクトと重なり得る点に注意が必要です。)

  1. *1

    Tables must not be used as layout aids. Historically, some web authors have misused tables in HTML as a way to control their page layout. This usage is non-conforming, because tools attempting to extract tabular data from such documents would obtain very confusing results. In particular, users of accessibility tools like screen readers are likely to find it very difficult to navigate pages with tables used for layout.

    https://html.spec.whatwg.org/multipage/tables.html#the-table-element
  2. *2 基本的にflow内でページ分割が影響しない事柄はXSLTが担う役目であるのでFO文書の不要な複雑化を避けられる制約でもあるのですが。
  3. *3 17–4 表のヘッダーとフッター 『XSL-FOの基礎 第2版』(アンテナハウス)
  4. *4 https://www.antenna.co.jp/AHF/help/ja/ahf-ext.html#axf.table-omit-header-at-break, https://www.antenna.co.jp/AHF/help/ja/ahf-ext.html#axf.table-omit-footer-at-break





瞬簡PDF 変換 2024
PDFをOffice文書へ高精度変換


瞬簡PDF 書けまっせ 2024
PDFに文字が書ける! 入力欄を自動認識

XSL-FO試行錯誤 fo:flow-mapの注意事項

前回、flow-mapの概要と、簡単な例、若干極端な利用方法と失敗例を紹介しました。

今回も注意深く使わなければ失敗してしまうという例を紹介します。

2つのregionであるregionA、regionBへ1つのflowを流し込むようなケースです。(というより、ほかの2つはこのパターンよりも複雑なので、利用しようとしたとき「うっかり失敗する」というケースは少ないのではないでしょうか。)

脚注はそれぞれのregionごとに配置される

一見1つのregion-bodyに見えますが、実は上下2つのregion-bodyで構成され、flow-mapでxsl-region-bodyを流し込んでいます。前回見たようにregionのサイズを超えるオブジェクトを挿入すると表示が壊れるかもしれませんし、あまりメリットがないように思えます。このflow-mapがどんなときに有用かというのは今後紹介するかもしれません。

とりあえず上手くいったように見えるFOですが、大きな欠点があります。

脚注をページ下部に配置するとき、正確にはregion-bodyのbottomから脚注の分の領域が確保されます。flow-mapはあくまでマッピングを行うだけで、region-bodyが1つになったわけではありません。つまり次のようなことが起こり得ます。

脚注をflow-mapで1つに見せかけたregionに流し込む
 <fo:flow flow-name="xsl-region-body">
   <fo:block >Lorem ipsum dolor sit amet<fo:footnote>
       <fo:inline ...>*<axf:footnote-number id="a"/></fo:inline>
         <fo:footnote-body>
           <fo:block ...>Lorem ipsum ...</fo:block>
         </fo:footnote-body>
     </fo:footnote>, consectetur ...
  </fo:block>
</fo:flow>

上部のregionAの下部に脚注は配置されました。たとえば左右に分けられているregionではそれぞれのregionの下部に表示してほしいでしょうし、当然の挙動ではあります。

複雑な回避方法を考えるよりも、このページシーケンスとflow-mapを使うときに「脚注を使用しない」「図表を使用しない」と制限した方が事故を防げるでしょう。
AH XSL Formatter拡張仕様ではregion-startやregion-endを注の配置に利用可能なので、「脚注ではなく傍注を利用する」といった方法も考えられます。

https://www.antenna.co.jp/AHF/help/ja/ahf-ext.html#axf.footnote-position

flow-mapで幅の違う疑似段組も実現可能だが、段抜きはできない

AH XSL Formatterではregion-bodyのほか、ブロックコンテナに段組を指定可能ですが、段組は通常段の行進行方向の長さが均等になります。
https://www.antenna.co.jp/AHF/help/ja/ahf-fo11.html#fo.block-container
flow-mapを活用することで、段の幅が異なる段組を擬似的に実現可能なのですが、span="all"を指定しても段抜きができないなど、これもまた使い所を考える必要があります。

幅の異なる(疑似)段組

これらのFOでは、表組などでもうっかり破綻する可能性があるので、くれぐれも注意深く使用しましょう。

参考資料


前々回:XSL-FO試行錯誤 脚注のインデント
前回:XSL-FO試行錯誤 fo:flow-map 概要編




瞬簡PDF 変換 2024
PDFをOffice文書へ高精度変換


HTML on Word
WebページをWordで作る!

XSL-FO試行錯誤 fo:flow-map 概要編

今回はflow-mapについてです。今回の記事は「概要編」としてflow-mapとはどんなものなのか紹介します。

region-bodyは複数記述可能

<fo:region-body><fo:simple-page-master>に複数記述可能です。region-body同士は重なり得るので、適切に配置します。<fo:flow>@flow-nameで利用するregion-bodyを指定します。

region-bodyを複数使う例

<fo:layout-master-set>
  <fo:simple-page-master master-name="main"
     size="JIS-B5 portrait" margin="10mm">
     <fo:region-body region-name="en" margin-right="182mm div 2 - 5mm"/>
     <fo:region-body region-name="jp" margin-left="182mm div 2 - 5mm"/>
   </fo:simple-page-master>
 </fo:layout-master-set>
 <fo:page-sequence master-reference="main">
   <fo:flow xml:lang="ja" flow-name="jp" >
     <fo:block ...>日本語</fo:block>
     ...
   </fo:flow>
   <fo:flow xml:lang="en" flow-name="en">
     <fo:block ...>English</fo:block>
     ...
   </fo:flow>
</fo:page-sequence>

region-bodyを複数使う例

たとえば、翻訳文を併記したいけれどテキストの長さが元の文と異なってしまうときなどにも対応可能ですね。表組や段組で左右の文の位置が揃うよう並べるよりも構造がすっきりしているのではないでしょうか。表組の解除や段抜きなどはないため、図版だけページ中央に表示したいなどの要求があるとややこしくなりますが。

flow-mapについて

本記事の本題はflow-mapです。名前の通りflowのマッピングを行える機能です。簡易な理解ではページシーケンスマスタでのページシーケンスとページマスタの関係を、flowとregionに置き換えたものとなります。ページシーケンスマスタのように条件よる参照分岐はできません。

XSL-FOの基礎 | 第4章 ページレイアウトの切り替え

JIS X 4179『拡張可能なスタイルシート言語(XSL) 1.1』で紹介されているflow-mapの使い方は3パターンほどです。簡単な例としては次のような形があります。

  1. 別々のregionであるregionA、regionBに対し、同じflowを流し込む
  2. 1つのregionに対し、別々のflowであるflow1、flow2を流し込む
  3. regionA、regionBにflow1、flow2を流し込む

この中でもっとも使い方として分かりやすいのは「regionA、regionBに対し同じflowを流し込む」という形でしょう。

flow-mapで2つのregionを1つのflowに対応させる
<fo:layout-master-set>
  <fo:simple-page-master master-name="complex"
     size="JIS-B5 portrait" margin="10mm">
     <fo:region-body region-name="regionA"
       margin-top="1cm" margin-bottom="130mm"
       margin-right="182mm div 2 - 5mm"/>
     <fo:region-body region-name="regionB"
       margin-top="180mm" 
       margin-left="182mm div 2 - 5mm"/>
   </fo:simple-page-master>
  ...
  <fo:flow-map flow-map-name="flowmap">
   <fo:flow-assignment>
     <fo:flow-source-list>
       <fo:flow-name-specifier flow-name-reference="flow-merged"/>
     </fo:flow-source-list>
   <fo:flow-target-list>
     <fo:region-name-specifier
       region-name-reference="regionA" />
     <fo:region-name-specifier 
       region-name-reference="regionB"/>
   </fo:flow-target-list>
   </fo:flow-assignment>
 </fo:flow-map>
<fo:layout-master-set>
<fo:page-sequence master-reference="complex"
  flow-map-reference="flowmap">
  <fo:flow flow-name="flow-merged"/>
    <fo:block>...
    <fo:block>
  &t;/fo:flow>
</fo:page-sequence>

flow-mapで2つのregionを1つのflowに対応させる

<fo:flow-map>@flow-map-nameを指定し、<fo:page-sequence>でそのflow-mapを参照するようにします。
流し込まれるソースのflowの@flow-nameと同じ値を<fo:flow-source-list>の子、 <fo:flow-name-specifier>@flow-name-referenceに、流し込み先のregionを<fo:flow-target-list>の子、<fo:region-name-specifier@region-name-referenceに指定します。今回はregion2つに対してflow1つを割り当てました。

<fo:page-sequence>@flow-map-referenceで参照するflow-mapを指定する必要があります。
複数flow-mapを用意すれば、同じflow-nameのflowに対し、flow-mapの参照を変更することで別のregionに流し込むことも可能です。

さらに細かいregionとflow-mapを利用することで、次のようなレイアウトも可能です*

沢山のregionをflow-mapで割り当てる

試行錯誤であるところはここからで、このregionはマッピングされているとはいえそれぞれ独立です。たとえばフォントサイズを大きくするとテキストの位置がずれ、次の行のテキストと重なるかもしれません。

一部のフォントサイズを変更した結果テキストが重なった