🕐

[DITA-OT]速習!preprocess2

に公開

はじめに

DITA-OTではDITAファイルを処理する際、メインの処理の前に加工を行います。このpreprocessは段階的に現行のpreprocess2への移行が進められてきました。

他の細かな点は置いて、特徴的な処理は次のものです。

  • DITAファイルを一時ディレクトリに置く際に入力元にあったディレクトリ階層を維持せずフラットな配置にする
  • この際にDITAファイルのファイル名をランダム・ユニークな値にする
    • フラットな配置ではファイル名を維持するとqux.ditag/qux.ditaのようなケースでファイル名が衝突して事故る

この処理について勉強中なので、整理記録を残します。

DITA-OTバージョンは4.3.3で実行しています。

入力ディレクトリ

今回入力にDITA-OTに付属するstartupサンプルを使用します。
展開フォルダに移動しinitサブコマンドで展開します。

dita init startup -o .
入力に使うディレクトリにtree /fを実行
│  project.ditamap
│
├─images
│      raccoon-1476504_960_720.jpg
│
├─publishing
│      publish-project.xml
│
├─reusables
│      reusable_components.dita
│      reusable_content.ditamap
│      reusable_keys.ditamap
│
├─themes
│      a4.yaml
│      base.yaml
│
└─topics
        welcome.dita

preprocess2の実行

(各値の初期化などを行うbuild-initと)preprocess2をdependsに置いたtaskを実行したとき、一時ディレクトリから実行結果を確認できます。
処理確認用にpluginのtranstypeを仮にcheckerとしたpluginを作成しておきます。

<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="https://www.dita-ot.org/rng/plugin.rnc" type="application/relax-ng-compact-syntax"?>
<plugin id="checker">
    <feature extension="ant.import" value="integrator.xml"/>
    <transtype name="checker" desc="check">
    </transtype>
</plugin>

ここで一点clean-preprocess.use-result-filenameの値がtrueであるとファイル名、ディレクトリ階層が一時ディレクトリ内でも再処理されてしまうため、「フラット配置、ユニークなファイル名」の確認できません。falseにします。

integrator.xml
<project>
   <target name="dita2checker" 
        depends="dita2checker.init,
        build-init,
        preprocess2
        "/>
    <target name="dita2checker.init">
        <property name="build-step.copy-image" value="false"/>
        <property name="build-step.copy-flag" value="false"/>
        <property name="clean-preprocess.use-result-filename" value="false"/>
        <property name="build-step.chunk" value="false"/>
    </target>
</project>

dita -f checker -i project.ditamapのようにしてdita2checkerが呼ばれると[1]dita2checker.init, build-init, preprocess2の順に処理が実行されます。

dita2checker.initではpreprocess2実行にあたってのパラメータを設定しています。

preprocess2の実行後の一時ディレクトリ

一時ディレクトリを確認するため、ditaコマンド実行時には--clean.temp=noを指定します。

dita -f checker -i startup -t ./tmp -o ./out --clean.temp=no

一時ディレクトリとして指定したtmpでtreeを実行してみます。

    .job.xml
    1cbb2402b7d406c4c7ee34849665cba4e76ed46d.dita
    460480f282da2c320bc7b7554b19b8df46fccb30.dita
    714caeff24c05e681c28bc69286864baf88a3717.ditamap
    ecd56f4e27c33c3903454049fc334f20ee60262f.ditamap
    ff969a152f720fc21fe32616e0501311904c2419.ditamap
    relflagimage.list
    usr.input.file.list

入力にあったtopicsreusablesのディレクトリは見当らず、乱数ファイル名のDITAトピックとマップファイル、そして.job.xmlreflagimage.listusr.input.file.listというファイルがあります。
また、マップやトピックからリソースとしても参照されていないpublishingやthemes下のファイルも見当りません。

usr.input.file.list

usr.input.file.list
714caeff24c05e681c28bc69286864baf88a3717.ditamap

直接の入力として使われたファイル名(の乱数化されたバージョン)がここに格納されます。
「1つだけなのにリスト?」と思いましたが、DITA-OT 4.3のやや地味なアップデートとして「入力ファイルを複数指定可能」(各々を対象としてビルド処理が各々に走る)があるので、それでしょうか。確認したら追記予定。

preprocess2後のマップファイル

では、このマップファイルを見てみます。本来改行がない箇所も改行したり、説明しない箇所を削ったりしています(デバッグ用とされている@xtrcxtrfとか)ので悪しからず。

preprocess2処理前がこちら。

project.ditamap
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE map PUBLIC "-//OASIS//DTD DITA Map//EN" "map.dtd">
<map>
  <title>Startup Project</title>
  <topicref href="topics/welcome.dita"/>
  <topicref href="reusables/reusable_content.ditamap" format="ditamap" processing-role="resource-only"/>
</map>
714caeff24c05e681c28bc69286864baf88a3717.ditamap
<?xml version="1.0" encoding="UTF-8"?>
<?workdir /C:\Users\hidar\work\tmp?><?workdir-uri file:/C:/Users/hidar/work/tmp/?><?path2project?>
<?path2project-uri ./?>
<?path2rootmap-uri ./?>
<?doctype-public -//OASIS//DTD DITA Map//EN?><?doctype-system map.dtd?>
<map xmlns:dita-ot="http://dita-ot.sourceforge.net/ns/201007/dita-ot"
    xmlns:ditaarch="http://dita.oasis-open.org/architecture/2005/" cascade="merge"
    class="- map/map " ditaarch:DITAArchVersion="1.3"
    domains="(map mapgroup-d) (topic abbrev-d) (topic delay-d) a(props deliveryTarget) (map ditavalref-d) (map glossref-d) (topic hazard-d) (topic hi-d) (topic indexing-d) (topic markup-d) (topic pr-d) (topic relmgmt-d) (topic sw-d) (topic ui-d) (topic ut-d) (topic markup-d xml-d)"
    specializations="@props/deliveryTarget" ...>
    <title class="- topic/title " ...>Startup Project</title>
    <topicref class="- map/topicref "
        href="1cbb2402b7d406c4c7ee34849665cba4e76ed46d.dita" type="topic">
        <topicmeta class="- map/topicmeta ">
            <navtitle class="- topic/navtitle ">My first topic</navtitle>
            <?ditaot gentext?>
            <linktext class="- map/linktext ">My first topic</linktext>
        </topicmeta>
    </topicref>
    <topicref class="- map/topicref " 
        href="460480f282da2c320bc7b7554b19b8df46fccb30.dita"
        processing-role="resource-only"
        type="topic">
        <topicmeta class="- map/topicmeta ">
            <navtitle class="- topic/navtitle ">Reusable Components</navtitle>
            <?ditaot gentext?>
            <linktext class="- map/linktext ">Reusable Components</linktext>
        </topicmeta>
    </topicref>
    <keydef class="+ map/topicref mapgroup-d/keydef " keys="product" processing-role="resource-only">
        <topicmeta class="- map/topicmeta " >
            <keywords class="- topic/keywords " >
                <keyword class="- topic/keyword ">DITA Project</keyword>
            </keywords>
        </topicmeta>
    </keydef>
</map>

元ファイルが10行無い程度なのに……。まあ、要素名の箇所を見ると大体何となく分かるかもしれません。

  • スキーマ検証によって、@class@domains@specializationsといった値が補われている(PSVI化)
  • <?workdir ...?>など処理命令が追加されている
  • topicref/@href.ditamap参照の中身が展開され、整合するようにマップに組み込まれている
  • @topicref/@href.dita内のmetadataの情報がtopicmetaに反映されている
    • 今回の場合<navtitle>もDITA-OTがトピックのtitleから補完しています

preprocess2後のトピックファイル

トピックファイルもこんな感じで、@hrefの値が更新されたり、処理命令が追加されたり、@class属性などが補完されたりといった感じになります。

ところがここで問題が1つ。画像ファイルの@hrefを抜粋します。

welcome.dita
    <image href="../images/raccoon-1476504_960_720.jpg" placement="break"/>
1cbb2402b7d406c4c7ee34849665cba4e76ed46d.dita
<image href="31d8db4c4c1e8f4acbe318af61910f0aa7f8c4bb.jpg" placement="break"
      class="- topic/image " />

画像ファイルの参照先が書き換わっているのに../images/raccoon-1476504_960_720.jpgをリネームした31d8db4c4c1e8f4acbe318af61910f0aa7f8c4bb.jpgは一時ディレクトリにコピーされていません。このままでは変換してビルドしてもファイル不存在で画像が使えない?

build-step.copy-imageをしていればこんなことには……とはなりますが、現在preprocess2を使用しているPDF2プラグインもbuild-step.copy-imagefalseです。これは、ファイル名とパスの対応を取って入力パスに書き戻しているのです。多分。

では、その対応を取っているファイルを見てみましょう。

.job.xml

あまりに長い<property>群は途中省略。<file>@uri@path@src@resultの値を見ると、対応が取れそうな雰囲気が伝わります。実際のところuripathの何が違うのかといった部分を明らかにしないと怖いのですが。

.job.xml
<?xml version="1.0" ?>
<job>
    <property name="user.input.dir">
        <string>C:\Users\hidaruma\work\startup</string>
    </property>
    <property name="transtypes">
        <string>xhtml;htmlhelp;pdf;pdf2;pdf.ng;eclipsehelp;html5;dita;validate;markdown;markdown_github;markdown_gitbook</string>
    </property>
    <property name="parser.md">
        <string>com.elovirta.dita.markdown.MarkdownReader</string>
    </property>
    ...
    <files>
        <file src="file:/C:/Users/hidar/work/startup/project.ditamap"
            uri="714caeff24c05e681c28bc69286864baf88a3717.ditamap"
            path="714caeff24c05e681c28bc69286864baf88a3717.ditamap"
            result="file:/C:/Users/hidaruma/work/startup/project.ditamap" format="ditamap"
            input="true"/>
        <file src="file:/C:/Users/hidaruma/work/startup/images/raccoon-1476504_960_720.jpg"
            uri="31d8db4c4c1e8f4acbe318af61910f0aa7f8c4bb.jpg"
            path="31d8db4c4c1e8f4acbe318af61910f0aa7f8c4bb.jpg"
            result="file:/C:/Users/hidaruma/work/startup/images/raccoon-1476504_960_720.jpg"
            format="image"/>
        <file src="file:/C:/Users/hidaruma/work/startup/reusables/reusable_content.ditamap"
            uri="ecd56f4e27c33c3903454049fc334f20ee60262f.ditamap"
            path="ecd56f4e27c33c3903454049fc334f20ee60262f.ditamap"
            result="file:/C:/Users/hidaruma/work/startup/reusables/reusable_content.ditamap"
            format="ditamap" resource-only="true"/>
        <file src="file:/C:/Users/hidar/work/ditatemp/reusables/reusable_keys.ditamap"
            uri="ff969a152f720fc21fe32616e0501311904c2419.ditamap"
            path="ff969a152f720fc21fe32616e0501311904c2419.ditamap"
            result="file:/C:/Users/hidaruma/work/startup/reusables/reusable_keys.ditamap"
            format="ditamap"/>
        <file src="file:/C:/Users/hidar/work/ditatemp/topics/welcome.dita"
            uri="1cbb2402b7d406c4c7ee34849665cba4e76ed46d.dita"
            path="1cbb2402b7d406c4c7ee34849665cba4e76ed46d.dita"
            result="file:/C:/Users/hidaruma/work/startup/topics/welcome.dita" format="dita"
            has-keyref="true" has-conref="true" has-link="true" target="true"/>
        <file src="file:/C:/Users/hidaruma/work/startup/reusables/reusable_components.dita"
            uri="460480f282da2c320bc7b7554b19b8df46fccb30.dita"
            path="460480f282da2c320bc7b7554b19b8df46fccb30.dita"
            result="file:/C:/Users/hidaruma/work/startup/reusables/reusable_components.dita"
            format="dita" target="true"/>
    </files>
</job>

relflagimage.list

flaggingで差し込む画像のパスを格納すると思われるがstartupのサンプルにはflaggingは使用されていないため、未検証。
要追記。

おわりに

実のところPDF用のmerge中間ファイルを自分でコントロールしたくてこの辺を確認したかったというモチベーションでした。

脚注
  1. plugin.xmltranstypeに設定した名前を***としてdita installを行った後dita -f ***を実行すると、dita2***というタスクを呼び出して処理が始まります。pluginのidではないので注意。 ↩︎

組版・ドキュメンテーション勉強会

Discussion