本当は怖いtopicref

DITAを初めて最初の頃にmapの中のtopicrefでprint="no"というのがあったら「印刷対象からはずしてください」とのリクエストがありました。まだまだ無知だったので、topicref[string(@print) eq "no"]のtopicrefは前処理で消してしまうようにしました。

でも良く考えるとこの処置は非常にイマイチでした。

1.reltableやrelated-linksでこの該当のtopicへのリンクがあった場合、それらが残ってしまいます。
2.同様にこのtopic内へのxrefがあった場合が考慮されていません。

1.は自動的に削除することが可能です。また2のxrefは本文中の要素なので削除はちょっと無理で警告メッセージを出すことができます。(本処理でまたエラーメッセージが出ます)

ですので、1,2は上記のとおりの対処をするようにして、更に該当するtopicは削除するようにしました。

しかしこの削除も少し大変で、あるtopicに対するtoipicrefがprint="no"となっていても、もしかしたら別のtopicrefでprint="yes"(もしくは無指定)で参照されている可能性があります。従ってあるtopicを削除して良いか否かは、そのtopicがprint="no"のtopicrefから参照されている場合のみにする必要がありました。

これでめでたしめでたしと考えたのですが、まだDITAはそれほど甘くはありませんでした。それはtopicrefというのは実は結構弾力的だということです。オーサリングするときの本当の書き方は<topicref href="[topicファイルのパス]/>ではなくて<topicref href="[topicファイルのパス]#[topicのid]/>です。

これがどのようなおそろしい意味を持っているかと言うと、mapから入れ子のtopicを参照できてしまうということです。最悪のシナリオ(!?)は次のようなものです。

イメージ 1


この例では、a.xmlに2つのtopicがあります。親のtopicはprint="no"のtopicrefから参照されています。入れ子のtopicはprint="yes"のtopicrefから参照されています。ですので、親のtopicを何も知らないで削除してしまうと、参照されている入れ子のtopicが(まさに入れ子構造なので)消えてしまいます。

従って、あるtopicを削除して良いかは、その入れ子のtopicがどこからもprint="yes"または無指定のtopicrefで参照されていない場合かを判断しなければなりません。

普通mapからこのように入れ子のtopicを参照するということはまずないです。お客様からも「ありえない」とは言われています。しかし実装はあらゆる場合に備えて厳格でなければなりません。プラグインは時間があったら修正したいと思います。