👏

DITAのfiltering・flaggingで製品バージョンによる分岐を扱いたい

2023/04/09に公開

さて、DITAアーキテクチャでは出力文書の表示制御について、filteringとflaggingという機構を用意しています。これらは文書中で特定のプロパティによってマークした構造について、外部から出力・表現を制御するものです。今回、日本語での記事が全然無さそうな部分について記述します。まとめとして、filtering・flaggingはグルーピングによる制御が可能です。これを用いて「製品1.x未満」「製品1.y以降」という制御を行う方法について紹介します。

あまり動作を確かめられていないので、怪しい記述があります。確認できたら修正していきます。

filtering・flaggingに使う属性についての補足

filtering・flaggingに利用するプロパティは次があります。これらはprofile属性という括りで扱われます。

  • @product
  • @audience
  • @platform
  • @otherprops
  • @rev

@revrevisionであるので、「これバージョンに使えそう」と思うのですが、『DITA概説書』では<q>revはflaggingに使え</q>(意訳)とあるんですよね。その反映か、@revだけditavalでは<revprop>を使うようになっています。

抑、製品のドキュメントを考えたとき「ここでの@revは何のrevisionなのか」というのがハッキリしないという問題があります。つまり、このプロパティだけでは次の2つを区別できません。

  • 文書の改訂版
  • 製品のバージョン

@otherpropsは独自の分岐処理、つまりは特殊化に利用可能ですが、製品ってバージョンも含めて1つの扱いな気もするので難しいところです。今回はproductを使います。

基本的なfiltering

productの値について、productAの製品は「productA+ver+バージョン」で示すとします。

<!-- DITAトピック内 -->
<p product="productAver1 productAver2">ProductAではhogeができます。</p>
<p product="productAver3">以前あったhoge機能は廃止されました。</p>

バージョン3用の出力をするなら次のようにditavalを用意します。

<!-- ditaval ファイル -->
<val>
  <prop att="product" value="productAver2" action="exclude"/>
  <prop att="product" value="productAver3" action="include"/>
</val>

「バージョンが増えると大変になりそう」というのは、薄々想像がつくのではないでしょうか。また、文書で扱う製品バージョンが増えたときに、修正箇所を把握しておくのが大変です。
長期に渡りメインテナンスされる文書では「ここはv1-v3まで」「ここはv2-v4まで」など複雑な構造になることがあります。単純なatt="product",value="..."では対応が大変ですし、filtering・flagging周りはユーザが独自に処理を追加するのが難しい箇所でもあります。

<!-- ver 20 用新機能用の ditaval ファイル -->
<val>
  <prop att="product" value="productAver2" action="exclude"/>
  <prop att="product" value="productAver3" action="exclude"/>
  <prop att="product" value="productAver4" action="exclude"/>
  ...
  <prop att="product" value="productAver20" action="include"/>

</val>

グルーピング

今回紹介するのは、ditavalの書き方が簡単になる方法です。@productの方は簡単になりません。

profile属性の値には<groupname>(value1 value2 ...)のようにしてグループ指定を利用できます。

OxygenXMLのサイトにあるサンプルによると、次がequivalentということらしいです。a,b,cは下のようになるのがこの時点ではしっくりきませんでしたが、ditavalを書く方で掴めるようになります。

product="a dataBase(dbA dbB) b appserver(mySERVER) c"
product="product(a b c) dataBase(dbA dbB) appserver(mySERVER)"

先に述べたように、DITAトピック文書側の記述は減りそうにないですね。肝心なのはここからで、これらをditaval側で指定するときにグループ名で指定できるようです。

<val><!-- ditavalでこう書けるようになる -->
  <prop att="dataBase" action="exclude" value="dbA"/>
  <prop att="product" action="exclude" value="a"/>
</val>

空のグループ名は無指定と同値のようです。

product="hoge()"
product=""

また、@product="dataBase(dbA)"@product="dbA"は異なるというのもポイントですね。
前者は@att="dataBase"@value="dbA"で扱うもので、
後者は@att="product"@value="dbA"で扱うものになります。

本題

これを製品バージョンに応用します。

  • ver3より前(ver1, ver2)のとき表示するパラグラフ
  • ver3以降で表示するパラグラフ
<p product="productVer(v1 v2)"> ...</p>
<p product="productVer(v3 v4 ... v20)"> ...</p>
<!-- ver 20のditaval -->
<val>
<!-- productVerにv2を含むものは除外、v3を含むものは残す -->
  <prop att="productVer" action="exclude" value="v2" />
  <prop att="productVer" action="include" value="v3" />	
</val>

保留 複雑なケース

上のグルーピングもケースによっては当然複雑になります。

<p product="productVer(v1 v2)">ある文脈</p>
<p product="productVer(v3 v4 ... v20)">ある文脈</p>
...
<p product="productVer(v1 v2 v3 v4)">別の文脈1</p>
<p product="productVer(v5 ... v20)"> 別の文脈1'</p>

<!-- コメント:v4から、文をv2以前と同様にしてみた -->
<p product="productVer(v3)">別の文脈2</p>
<p product="productVer(v1 v2 v4 v5 ... v20)"> 別の文脈2'</p>

「別の文脈1」のv4以前とv5以後で処理が変わるものについては、v3でinclude指定したものをv20など、被らないものにすればよいでしょう。

「別の文脈2」はどうでしょう。「v1,v2が今度はincludeに、v3がexcludeになるようにしたい、しかし「ある文脈」ではv1,v2はexcludeだし……」と混乱しますね。

specでの例示では、複数のグループで矛盾する処理が記述されているケースなども扱っていますが、hidarumaが咀嚼できていないため説明を保留します。

おまけ branch filtering

DITA 1.3以降では、<topicref>の子に<ditavalref>でditavalを指定し、ditavalの内容に沿って処理された結果をtopicとして扱うことができます。

例としてspecにあるものの一例を挙げてみます:

1. platform属性でwin,mac.linuxで個別のパラグラフを用意したトピック
2. それぞれをinclude,excludeするditavalを用意
3. 同じトピックを@hrefに指定する<topicref>を3つ用意
4. それぞれの子に、先に用意したditavalをditavalrefで指定
5. 必要ならそれぞれに参照時に使うsuffixなどを指定可能
6. ditavalを反映した結果がそれぞれ別のトピックとして扱われる

参考資料

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

Discussion