カテゴリー別アーカイブ: XSL-FO・CSS

XSL-FO試行錯誤 スライドPDFをXSL-FOで組む

以前に、スライドをXSL-FOで作成した例をご紹介しました。
今回、明日9/17(金)17時よりオンライン開催される「FormatterClub2021」用のスライドを改めてXSL-FOで作成したのでご紹介します。

まずは明日の宣伝です。

FormatterClub2021ウェビナー

【どなたでも無料視聴可能】

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

今回はPowerPointで下書きを作成した後、清書をXMLで行い、XSLTでXSL-FOに変換するという方法を取っています。以前のウェビナーではPowerpoint原稿をそのまま使ったのですが、見出しや各箇所の文字サイズといった、同じ内容の繰り返しが多い事柄に対し個別に変更を行っていくのはちょっと辟易してしまったためです。
Powerpoint文書もXMLの集合ではあるのですが、PresentationMLはとくにDrawingML色が強く、いってみればグラフィカルな配置に重点が置かれているため、「流し込んだら良い感じに自動配置してほしい」といった要求のための元テキストを得るのは恐らくWord以上に困難です。

XSLTのバージョンは3.0で動かしています。記事中に登場するFO、XSLTの動作について保証するものではありません。ご了承ください。

XML

次のようなXMLからXSL-FOを生成します。

<section xml:id="about"><title>概要</title>
   <div style="slide" layout="cover" />
 ...
   <div style="slide" layout="fig-desc">
   <description>
     <dl>
       <dlentry>
         <dt>書名</dt>
         <dd>AH XSL Formatter拡張仕様使いこなしガイド</dd>
       </dlentry>
       <dlentry>
         <dt>公開日</dt>
         <dd>2021年5月18日</dd>
       </dlentry>
       <dlentry>
         <dt>概要</dt>
         <dd>XSLをAH XSL Formatterが独自に拡張した仕様についてのガイド
           <list style="unordered">
            <li>複合的なショウケース</li>
            <li>「やりたいこと」から引ける逆引きリファレンス</li>
          </list>
        </dd>
      </dlentry>
     </dl>
   </description>
   <figure>
      <image href="./XSL-FO-Extensions.png"/>
   </figure>
 </div>
 <div style="slide" layout="plain">
 ...
 </div>
</section>
...

若干の制限を設けたブロックとしてdescriptionタグを用意していますが、概ねHTML5程度の表現力のXMLを用意しました。汎用タグdivで何でも表そうとすると、子や親の要素・属性に制限を設けることが難しいという欠点にぶつかります。

dlentryはdtとddの組を区切るのに使用しています。HTML5のようにdivでないのは上と同じ理由です。区切りを前提にすることによってXSLT上でのパースがかなり楽に行えます。

ulとol相当はlistのclassとして使い分けます。CommonMarkのDTDなどはこのように扱っていますね。

テーマ擬き

Powerpoint、あるいは多くのプレゼンテーション用ソフトには「テーマ」という、スタイル設定の集合があります。
Word文書などと同様、Powerpoint文書はレイアウト用と見た目用の構造が渾然一体となっているのでテーマ切り替えだけでは大抵万事上手くは行かず適宜調整することになります。とまれ、見た目上の違いが印象に大きな影響を与えるスライド文書では類似の機構があると便利です。

今回は次のレイアウトを用意しました。

  • 「表紙用レイアウト」
  • 「大項目扉ページレイアウト」
  • 「通常ページレイアウト」
  • 「段組レイアウト」
  • 「画像とその説明用レイアウト」
  • 「大きめの画像表示レイアウト」

大きく異なるレイアウトについては異なるページマスターとして用意します。
通常ページ、段組、画像とその説明、大きめの画像表示レイアウトは同一のページマスターです。また、スライド全体の表紙と、大項目扉ページは同一のページマスターです。両者の違いは、fo:region-startfo:region-beforefo:region-afterの領域の有無、またそれを考慮したfo:region-bodyであるかです。

表紙系のページ

表紙以外のページ

(AH XSL Formatter拡張仕様ではページシーケンスの入れ子が行えるので「同じ項目内容の途中でスライドのレイアウトを切り換える」という要求を簡単に満たすことができます。この辺りも元のXML構造の設計に影響します。)

表紙系でないページでは、小項目のタイトルをfo:region-beforeに表示することにします。スライドではヘッダーとしての表示と見出しとしての表示を兼用してもあまり違和感がありませんね。また、大項目をfo:region-startに配置します。16:9のスライドの場合、画面の左端から右端までが4:3に比べ遠くなるため、タイトル領域として活用することにしました。こうすることで、大項目と小項目を両方表示したいとき、1つのヘッダーに大項目と小項目を両方表示するよりも、あまり文字を小さくせずにすみます。

段組レイアウトはAH XSL Formatter拡張仕様であるブロックコンテナへのcolumn-count指定で実装しました。

画像とその説明用のレイアウトはインラインコンテナを並べて実装しています。インラインコンテナは分離しないよう、念のためkeep-with-*などを指定します。幅指定を行わないと2つめのインラインコンテナが次の行へ送られてしまったり、高さ指定を合わせておかないとline-stacking-strategyによっては配置がガタガタしてしまいますから注意が必要です。

画像とその説明用のレイアウト
<fo:block>
 <xsl:attribute name="line-stacking-strategy">line-height</xsl:attribute> 
   <fo:inline-container width="48%"
     height="100%"
     keep-with-next.within-line="always">
     <fo:block>
        <xsl:apply-templates select="child::description"/>
     </fo:block>
   </fo:inline-container>
   <fo:inline-container width="50%" height="100%">
     <fo:block>
       <xsl:apply-templates select="child::figure"/>
     </fo:block>
   </fo:inline-container>
 </fo:block>

ほかの方法としては、「region-bodyを複数用意してflow-nameを切り換える」、「画像を左右へのフロートで配置する」といったものが考えられます。フロート配置は王道ですが、スライド用途の場合、AH XSL Formatter拡張でなければ思ったように(目的のスライド位置に)配置することはかなり難しいかもしれません。

箇条書き

スライドでは箇条書きが頻出する傾向があります。端的に内容を示し、口頭でのプレゼンに詳細内容を譲るためなど理由は考えられますが「様々な場所で登場する」ということに留意する必要があります。

XSL-FOのリスト構造はstart-indentとend-indentが肝要です。

ブロックのインデントは基本的には親の値を引き継いでいれば問題ありませんが、start-indentを指定したブロックの入れ子にリストブロックがあるケースなどでは、うっかり領域の端からの値にならないよう、inherited-property-value(*-indent)で親のインデントの値を取得してから自分のインデントを追加する必要があります。

<!-- 入れ子レベル$listLevelは計算済 -->
...
<xsl:attribute name="provisional-distance-between-starts">
 <xsl:value-of select="'inherited-property-value(start-indent) + 0.5em + ' || $listLevel || 'em'"/>
 </xsl:attribute>

fo:list-item-labelの内部はブロックなので、ラベルに使える記号の自由度は高いです。今回は入れ子レベルによるラベルの切り換えは行いませんでした。

定義箇条もリストブロックにしました。同じDL内のDTの文字列長を比較し、最長のものを基準にインデントを決定しています。あまりにDTが長ければ単純なブロックに切り換えます。今回は和欧混合文などは考慮しません。


<xsl:template match="dl">
 <xsl:variable name="dt-lens">
   <xsl:for-each select="child::dlentry/dt">
     <len>
        <xsl:sequence select="xs:double(string-length(./text()))"/>
     </len>
   </xsl:for-each>
 </xsl:variable>
 <xsl:variable name="max-length-dt" select="xs:integer(max($dt-lens/len/text()))"
   as="xs:integer"/>
 <xsl:choose>
   <xsl:when test="$max-length-dt &lt; 20">
     <fo:list-block
       provisional-distance-between-starts="inherited-property-value(start-indent) + {$max-length-dt}em + 2em"
       provisional-label-separation="1em">
        <xsl:for-each select="child::dlentry">
           <fo:list-item>
             <fo:list-item-label ...">
                <fo:block ...>
                   <xsl:apply-templates select=".//dt"/>
                </fo:block>
             </fo:list-item-label>
             <fo:list-item-body ...>
                <fo:block ...>
                   <xsl:apply-templates select=".//dd"/>
                </fo:block>
             </fo:list-item-body>
           </fo:list-item>
         </xsl:for-each>
     </fo:list-block>
   </xsl:when>
   <xsl:otherwise>
    ...
   </xsl:otherwise>
  </xsl:choose>
</xsl:template>

最長である「公開日」の長さを基準にインデントが決定されています。均等割り付けの指定は「:」を含んでしまっているので「概要」の後のスペースなどはちょっと微妙です。end方向に揃えるか、axf:text-autospaceで揃えるか、ブロックの横にフロートかブロックコンテナで「:」配置すればより良くなるでしょう。

枠内にテキストを収める

大項目の扉ページでは、見出しテキストを四角い枠内に収めることにしました。

スライドは本と比べ、ページごとの独立性が高くなることが多いでしょう。「1枚の中に必要なコンテンツを収めたい」というとき、フォントサイズや字間、伸縮などを最適なものから外しても1枚のスライド内に収めるため、オーバーフロー処理を記述します。

どうにかテキストを枠内に収めるにしても限界値はあります。より汎用的に使うのであれば、文字数制約や、枠自体のサイズを指定し直すような記述を追加することになるでしょう。


今回採用、実装しなかったものとしては「自由配置の吹き出し」や「画像の上から付ける下線」などがあります。グラフィカルな配置はスライドとしても重要な要素ですが、代用が可能なものでもあります。たとえば画像側で下処理を行っておけば、清書としては都度処理する必要はありません。
とはいえ、まったくそれらの処理ができないのも不便ではあります。
今後、このようにXMLからPDFスライドを作成する機会があれば、SVGやブロックコンテナをページ上の座標など簡単なパラメータで任意の場所に配置するような形態で実装するかもしれません。

関連記事





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


瞬簡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をOffice文書へ高精度変換


アウトライナー
PDFを解析して しおり・目次を自動生成

XSL-FO試行錯誤 SVGでもっとグラフィカルなボーダーを

Antenna House Formatterではボーダーに指定可能な線種について大きく拡張されています。

しかし、それでもボーダーの意匠について自由自在とまでは行きません。
例えば「ロープで結ったような枠線を出したい」というときには、背景画像を置くことになるでしょう。ボーダーの扱いで(他の多くと同様に)難しいところは、ページ分割のときにどうするかです。
背景画像に固定枠の画像を指定したとき、段落の長さによって枠をずらすようなことはできませんね*。ページ分割時にbeforeとafter部分のボーダーを再表示する必要がなければ、段落の前後に画像を挟めば良いだけで、テーブルレイアウトにする必要はありません。

さて、XSL-FO試行錯誤シリーズ、以前の回でテーブルレイアウトを駆使してブロックがページ分割されるごとに特定の要素を出現させる方法を紹介しました。
つまり、テーブルレイアウトのヘッダとフッタにボーダーとなる画像を指定し、テーブルのボディのbeforeとafterの位置に表示させてやろうというのが今回の試みです。

やることは単純明快。ソースコードは単純とはいきませんが。
早速結果を見てみましょう。

可変長の段落に対応した装飾的なボーダー

今回のソースコードは(特に)色々無駄があります。見ながら一緒に突っこんでいただければ幸いです。

ソースコード
<fo:block-container>
  <fo:table table-omit-header-at-break="false" table-omit-footer-at-break="false">
    <fo:table-header>
      <fo:table-row>
        <fo:table-cell>
          <fo:block-container 
            absolute-position="absolute"
            top="-2cm" left="-2.6cm"
            width="100%" height="6cm"
            axf:background-content-height="scale-down-to-fit"
            background-image="url(./corner.svg)"
            axf:background-size="cover">
          </fo:block-container>
        </fo:table-cell>
      </fo:table-row>
    </fo:table-header>
    <fo:table-footer >
      <fo:table-row>
        <fo:table-cell>
          <fo:block-container 
            width="100%" height="10cm">
            <fo:block-container
              absolute-position="absolute"
              top="-4cm" left="3cm"
              width="100%" height="10cm"
              axf:background-content-height="scale-down-to-fit"
              axf:transform="rotate(180)"
              background-image="url(./corner.svg)"
              axf:background-size="cover">
           </fo:block-container>
         </fo:block-container>
       </fo:table-cell>
     </fo:table-row>
   </fo:table-footer>
   <fo:table-body>
     <fo:table-row>
       <fo:table-cell>
         <fo:block space-before="4cm"
           space-before.conditionality="keep" start-indent="2cm" end-indent="2cm">
 Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

...
 
         </fo:block> 
       </fo:table-cell>
     </fo:table-row>
   </fo:table-body>
  </fo:table>
</fo:block-container>

思いつきのままに書いたのでもっとやりようがある気もします……。

corner.svgがボーダーとして用いる画像です。上のコードのように、わざわざaxf:transformで回転するよりも、もう1つフッタ位置用の画像を用意した方が早いでしょう。

ボーダー分、段落のbeforeにスペースを空けています。ボーダー画像を背景に指定しているブロックコンテナにabsolute-positionを設定しているためで、ブロックとfo:external-graphicでボーダー画像を配置した場合は不要です。SVGのサイズをきちんと把握して作成しておけば、もっとスッキリした指定になるでしょう。
background-sizeにcoverを指定していますが、coverである必要もないですね。左上の画像は高さの指定と合わず切れているので怒られかねません。

今回はbeforeとafterのボーダーに注目しました。ではstart、endのボーダーはどうすればいいのでしょうか? これは実はより単純で、背景に指定したボーダー用の画像をbackground-repeatでブロック進行方向に繰り返すことで、ある程度可変長の段落に対応できるようになります。ただ、ボーダー画像の端で上手く繰り返せるように段落の高さが背景画像の高さの整数倍になるようにする、beforeとafterのボーダー画像と破綻しないようにする、といった調整が必要になるでしょう。
beforeとafterについては背景画像ではなくfo:external-graphicやfo:internal-graphicでもあまり問題はないのですが、startとend方向は繰り返しの指定上背景画像への指定が良いのではないでしょうか。

* 後から検討したのですが、背景画像を指定した複数のブロックコンテナを入れ子で記述して描画位置を調整すればある程度可能そうです。結局ページ分割の問題にあたってしまいますが。

DITAで本を書いてAH XSL Formatterで自動組版する

日時
2021年8月10日(火)16:00~17:00
概要
2021年5月18日に公開/販売した『AH XSL Formatter 拡張仕様使いこなしガイド』の制作報告を通し、XML執筆からPDFを作る過程の知見をご紹介します。
DITAについてや、DITAでの書籍制作における実例の紹介や、DITAを扱うときの注意事項など、自動組版やXMLの使い方、DITAに興味がある方、Formatterユーザーさん、必見です!
内容紹介・お申込みページ
こくちーずプロからお申し込み:https://www.kokuchpro.com/event/20210810/
Zoomウェビナーへ直接お申込みいただく場合: ウェビナー登録ページ





アウトライナー
PDFを解析して しおり・目次を自動生成


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

【ちょっと一息アンテナハウスウェビナー】「DITAで本を書いてAH XSL Formatterで自動組版する」を開催します【8/10】

本ウェビナーは終了しました。

の「ちょっと一息アンテナハウスウェビナー」の告知ページが公開されましたので、当ウェビナー担当者から、ブログ記事でもお知らせします。


DITAで本を書いてAH XSL Formatterで自動組版する

日時
2021年8月10日(火)16:00~17:00
概要
2021年5月18日に公開/販売した『AH XSL Formatter 拡張仕様使いこなしガイド』の制作報告を通し、XML執筆からPDFを作る過程の知見をご紹介します。
DITAについてや、DITAでの書籍制作における実例の紹介や、DITAを扱うときの注意事項など、自動組版やXMLの使い方、DITAに興味がある方、Formatterユーザーさん、必見です!
内容紹介・お申込みページ
こくちーずプロからお申し込み:https://www.kokuchpro.com/event/20210810/終了しました
Zoomウェビナーへ直接お申込みいただく場合: ウェビナー登録ページ終了しました

元々制作報告については何らかの形で行っていく予定でしたが、この度ウェビナーの形で紹介することになりました。

さて、「ちょっと一息アンテナハウスウェビナー」は平日にお時間をいただくこともあり、時間的にはかなりコンパクトになっています。『AH XSL Formatter 拡張仕様使いこなしガイド』の制作にあたっては、トピックとしては「XMLのこと」「XSL-FOのこと」「XSLTのこと」「PDFのこと」「DITAのこと」「学習にあたって参考にした資料のこと」「入稿のこと」「Antenna House XSL Formatterのこと」「原稿、レビューなどの社内環境のこと」など色々とあり、小さくまとめるのはなかなか難しいのですが、今回のウェビナーでは「既存資産がDITA文書ではない状況で、DITAを原稿とした書籍制作の報告」を軸に行う予定です。

上のように書き出してみるとよく分かりますが、XML組版、そしてそれに関連する技術を使うためには押えておく事項が多く「1から10まですべてやる」というのはかなり体力が必要です。自動組版を検討するにあたって「文書作成から組版までのどの過程を自分たちで行い、どの過程を自分たちではやらないようにするか」を判断する一材料としてもお役に立てるかもしれません。

ウェビナー開催まで少し期間がありますので、ご満足いただけるよう鋭意準備を進めていきます。





アウトライナー
PDFを解析して しおり・目次を自動生成


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

XSL-FO試行錯誤 最初からハイフンのある語の制御

5月18日に『AH XSL Formatter拡張仕様使いこなしガイド』が公開・発売したことは
当日の記事で述べました。

『Antenna House XSL Formatter 拡張仕様使いこなしガイド』を公開・発売しました I Love Software2!

『XSL-FO 試行錯誤』連載ではこれまで密かに「AH XSL Formatterの拡張仕様はメインの対象にしない」という縛りでやってきたのですが、めでたく書籍が公開されましたので、これからは拡張仕様についても対象にしていきます。『AH XSL Formatter 拡張仕様使いこなしガイド』に載せられなかった話題について扱うかもしれません。たとえばAH XSL FormatterではCSS3にあるような装飾表現が可能であったりするのですが「CSS3を紹介したWebサイトを見れば良いのでは」となってボツにしたものがそこそこあります。

制作のXSL-FO以外の面についての話についても折を見て記事などで展開する予定です。気になった点などがあればコメントやSNSなどで言及していただければ反映できるかもしれません。

最初からハイフンのある語の制御

ということで、本記事の話題は見出しの通り。どういったものがあるかというと、コマンドラインのオプション引数(-optionとかですね)、XSL-FOの要素、プロパティ名など(border-top-styleなど)ですね。

そもそもこれらは行分割位置に来ないようにするのがおそらく理想的ですが、ページ数の制約などで妥協することもあるかもしれません。

もとからハイフンがある語は分割によるハイフンを追加しない

<fo:block ...
 hyphenate="true"
 axf:hyphenate-hyphenated-words="false">...
</fo:block>

サンプルFOのページのサンプルでもよく使われています。プロパティ名など、もともとハイフンを含む語にハイフンが追加されてしまうと、元からあったハイフンなのか、分割時に追加されたハイフンなのか分からなくなってしまうかもしれませんからね。

他の回避手段としては、ハイフネーションとして追加される記号を変更するという方法も考えられます。

ハイフンを含む特定の文字列を、分割可能でないハイフンに置き換える

(XSL-FOの標準仕様として、「行分割でハイフンが追加され得る単語で、分割前後の文字数によって分割位置を調整する」ことができるhyphenation-remain-character-counthyphenation-push-character-countがあります。)

さて、元からハイフン(-)を含む語があり、初期設定でこのハイフンの後では分割可能であるとします。しかし、この文字の後が1字のみのとき(「UTF-8」など)のとき、「8」だけ次の行にいくのはあまり望ましくないですね。

「分割しないハイフン(NON BREAKING HYPHEN)」(U+2011)という文字があります。この文字でハイフンを置き換えてあげれば、ハイフンの前後で行分割は通常起こりません。
では、すべてのハイフンを置換しますか? それはそれで文字数の調整が狂ってしまいかねません。
また、元のファイルが500ファイル以上になっていたので、時間的に個別に置換するのはちょっと困難だとします。

今回は「特定の文字の組み合わせ(-*)でのみ、1字の次行送りが発生する」ことが分かっていたので、axf:text-replaceを使うことにしました。

axf:text-replace / CSS (-ah-)text-replace AH Formatter マニュアル


<xsl:attribute-set name="code">
<xsl:attribute name="axf:text-replace" select="'-&#x2217;' '&#x2011;&#x2217'"/>
</xsl:attribute-set>

指定に確認していない漏れがなければ上手く行っているはず。


この成果(書籍全体で適用されているか)は『AH XSL Formatter 拡張仕様使いこなしガイド』で確認してください!
(XMLファイルを処理するときにXSLTは経由したわけで、XSLT 2.0の正規表現などによる置換なども可能ですが、その辺りをあまり変更したくない、変更できない場合、ありますよね?)


『AH XSL Formatter 拡張仕様使いこなしガイド』





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


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

『Antenna House XSL Formatter 拡張仕様使いこなしガイド』を公開・発売しました

に『Antenna House XSL Formatter 拡張仕様使いこなしガイド』を公開しました。


Antenna House XSL Formatter 拡張仕様使いこなしガイド | AH Formatter XML関連出版物の紹介

また、弊社Webページで公開しているPDF版のほか、AmazonのPrint On Demand(POD)により印刷版をお買い求めいただけます。

Antenna House XSL Formatter 拡張仕様使いこなしガイド | Amazon

書籍の概要や目次についての詳細は紹介ページに掲載されていますが、この記事では少し短くまとめて紹介します。

本書は、W3C勧告のExtensible Stylesheet Language(XSL)1.1のFormatting Object(FO)から、アンテナハウスが独自に拡張した機能について解説しています。本書は次の4章構成です。

  1. 『ショウケース』
  2. 『Antenna House XSL Formatter 拡張仕様と応用例』
  3. 『PDF出力』
  4. 『その他の拡張』

『ショウケース』はAntenna House XSL Formatterを利用してどのようなレイアウトが可能であるのか、サンプルをどんと出してから、どのようにXSL-FOを記述しているかを項目に分けて説明しています。



『AH XSL Formatter 拡張仕様と応用例』では拡張仕様によって可能になる文書構造、利用例を逆引きで掲載しています。「行いたい表現」から対応する仕様を探す際などにお役に立てていただくことを想定しています。

『PDF出力』『その他の拡張』も拡張仕様の逆引き項目を主内容としますが、PDFに特化した機能は多岐に渡り、セクションでまとめるには大変な量となってしまうため、章として独立しています。『その他の拡張』は印刷やオプション設定など、文書内部とは関連の薄い項目をまとめています。

それぞれのトピックは、ほかのトピックへの言及は極力避け、目次、または最後に配置した仕様一覧へと頻繁にアクセスすることを想定した構成になっています。

さて、本書自体もAntenna House XSL Formatter V7.1改訂2版を用いて制作されています。
LwDITAで下書きを行い、DITAに変換し調整、修正を行った後、DITA-OTとPDF5-MLを基に拡張したプラグインでFOに変換、Antenna House XSL FormatterでAmazon PODの要求する仕様に沿ったPDFを出力、という工程です。この詳細についてはまたブログなどでまとめられればと思います。

Antenna House Formatterでは試用版をご用意しています。XSL-FOによる組版、そして本書で紹介しているような拡張を試用してみたい方はぜひお申込みください。
AH Formatter 評価版のお申し込み





アウトライナー
PDFを解析して しおり・目次を自動生成


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

XSL-FO試行錯誤 索引でページ番号をmergeできるのは3ページから

XSL-FOの索引でページ番号が連続するとき、最初と最後のページ番号だけ表示して途中のページを省略するプロパティがあります。

  • 索引キーが連続するページに登場する
  • 索引キーのindex-classが同じである(index-classが異なるとマージ処理が指定されていても分離される)
  • merge-ranges-across-index-key-referencesプロパティ”merge”が設定されている

このときmerge-sequential-page-numbersmergeを指定いると、ページ番号表示が範囲形式にまとめられます。範囲形式のときに最初のページ番号と最後のページ番号の間の文字は<fo:index-page-citation-range-separator>で指定可能です。

仕様にも「3ページ以上のとき」とあり、2ページのときはとくに何もしません。

この機能は、索引に指定した語の登場ページを列挙するときに表示をまとめる機能であり、「トピックと語がほぼ一致するので、索引表示はトピックの範囲が分かるようにしたい」という要望のためのものでは「ない」ということです。
具体的には、筆者は「2ページ連続のときも範囲形式で表示したい」とFOを記述しようとして「そういう機能ではない」という指摘を受けました。

ちなみに「トピックの範囲を常に範囲形式で表示したい」というときはどうするかについては、「トピックは必ず2ページ以上となる」という制約を付けられるのであれば(見開き2ページを基本構成とするなど)、<fo:page-number-citation>を使えば良いでしょう。制約がないと、トピックが1ページの範囲のとき「3ページ-3ページ」のような表示になってしまうかもしれません。(<fo:static-content>内のマーカ参照でのこういった重複については、AH XSL Formatterではaxf:suppress-duplicate-marker-contentsという拡張仕様があります。)


索引 22–2–2 連続ページ番号の範囲表示 | XSL-FOの基礎 第2版

索引自体の記述例はサンプルFOをご覧ください。
https://www.antenna.co.jp/AHF/ahf_samples/sample-fo.html#page-set




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


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

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に文字が書ける! 入力欄を自動認識


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

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を自由自在に編集


瞬簡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ソフトの統合製品!


HTML on Word
WebページをWordで作る!
Pages: Prev 1 2 3 4 5 6 7 8 9 10 11 12 Next