fo:list-block

今回はfo:list-blockについて紹介します.fo:list-blockはXSL-FOでリスト状のレイアウトを行うときに使用する親要素です.普段Wordなどでは番号つきリストや番号なしリストは実際には段落の特殊な形態なで表されていますが、XSL-FOではfo:blockとは違うfo:list-blockというオブジェクトがちゃんと用意されています.
XSL-FOのリストモデルを図で示します.
 
イメージ 1
 
XSL-FOで図のような表示を行うには例えば次のような記述が必要になるでしょう.
 
<fo:list-block start-indent="5mm" provisional-distance-between-starts="7mm" provisional-label-separation="1mm" >
    <fo:list-item>
        <fo:list-item-label end-indent="label-end()">
            <fo:block>1.</fo:block>
        </fo:list-item-label>
        <fo:list-item-body start-indent="body-start()">
            <fo:block>XML is established as the universal standard for delivering documents on the web.</fo:block>
        </fo:list-item-body>
    </fo:list-item>
</fo:list-block>
 
これからわかるように、リストは実はラベルとボディの2つの部分から構成されています.fo:list-blockのprovisional-distance-between-startsとprovisional-label-separation、fo:list-item-labelのend-indent="label-end()"、fo:list-item-labelのstart-indent="body-start()"はXSL-FOのリストのおまじないみたいなものです.2つのラベルとボディのブロックをFormatterはこの4つのパラメータから配置を決めてレイアウトしてくれます.
 
計算は(普通は)こんな感じになります.
 
label-end()=本文領域の幅 - (provisional-distance-between-starts + fo:list-labelのstart-indent - provisional-label-separation)
bod-start()=fo:list-labelのstart-indent + provisional-distance-between-starts
 
リストのラベルの内容は自分で設定しなければなりません.番号なしリストなら単に行頭文字の"・"を置くだけですみますが、番号つきリストの場合は、<li>の数をカウントします.このあたりはxsl:numberという便利な要素がXSLTに用意されているのでそれほど難しくはないでしょう.
さてリストについては二点ほど覚えておいた方がよいことがあります.
 
■ fo:list-itemのrelative-align属性
XSL-FOの仕様を読むと、fo:listitem(リストの各要素)に次のような記述があります.
 
"The children of each normal area returned by an fo:list-item formatting object returned by the fo:listitem-label and fo:list-item-body objects are positioned in the block-progression-direction with respect to each other according to the relative-align trait."
 
なにやらチンプンカンプンかもしれませんが、実はfo:list-itemの子のfo:list-item-labelとfo:list-item-bodyには、ブロックの進行方向(行の増加する方向)に「揃え」がかかっているのです.これを表すのが、fo:list-item/@relative-alignです.初期値はbeforeで、fo:list-item-labelとfo:list-item-bodyの「上辺が揃い」ます.ですから、もしfo:list-item-labelの"1."のフォントサイズをfo:list-item-bodyのそれより大きくすると、ラベルとボディでベースラインが揃わなくなります.もし、このような場合でベースラインを揃わせようとしたら、fo:list-item/@relative-align="baseline"と指定しなければなりません.下の例では、"1"はreltive-align="before"で"2."はreletive-align="baseline"です.
イメージ 2
 
あとこのような制約のために、例えばfo:list-item-labelに画像を置いてリストを作り、右のボディとバランスするように上下位置を調整しようと、baseline-shiftプロパティを変化させても画像は上下に動いてくれません.このようなときはline-heightの値で調整します.
 
■ fo:list-itemのspace-beforeとspace-after
これもよくあるパターンなのですが、fo:list-item/fo:list-item-bodyの子要素にfo:blockを配置して、space-beforeを指定しても最初のfo:block/@space-beforeは「効いてくれません」また同じように最後のfo:block/@space-afterも「効いてくれません」.これは、fo:list-itemについては、XSL-FOの仕様で
 
"The block-progression-dimension of the content-rectangle of an area generated by the fo:list-item is just large enough so that the allocation-rectangles of all its child areas are contained in it. In particular, the space-before and space-after of the child areas have no effect on the spacing of the list item. For purposes of the block-stacking constraints the areas generated by fo:list-item are treated as if there they have a fence preceding and a fence following them."
 
とされていてfo:list-itemの「へり」では、子のfo:blockのspace-beforeとspace-afterが影響しないようになっているからです.(これも初心者にはチンプンカンプンですが)ただしfo:list-item自身に設定されたspace-beforeとspace-afterは効いてくれます.
 
このため、例えばspace-beforeベースのレイアウトでli/pというような構造があった場合、pから生成しようとするspace-beforeをfo:list-itemに転記してやる必要があります.とはいえ、liを処理する時にこれを行わなくてはなりませんので、liの処理ではfo:list-itemを生成するときに自分の最初の子要素が何で、いかほどのspace-beforeを適用すべきかを判定しなければなりません.これはスタイルシートにはちょっと手のかかる仕事です.
 
fo:list-blockは、番号つきリストや番号なしリストだけでなく、部や章の表題でも使われます.例えば"第NN章. 「章題」"とするとき、「章題」が長いようだとやはり、""第NN章."の手前で折り返したいものです.このような場合にもfo:list-blockが使われます.しかしfo:list-item-labelの幅をどのような場合にもバランスよく調整するのは結構難しいものです.