属性の特殊化

九州地方地震で被災された方をお見舞いします.遅ればせながら災害募金をさせていただきました.

さて、掲題の属性の特殊化ですがずっと長い間理解が行き届いておらず、恥ずかしながらとんでもない遠回りをしていました.それは、GitHubで公開しているah-ditaの特殊化です.ah-ditaの特殊化は簡単に言えば、DITAのありとあらゆる要素でXSL-FOの属性(XSL-FOではプロパティと呼ぶ)を指定可能にし、可能なものにはそれをプラグインスタイルシートで最終的に生成されるXSL-FOに反映させようとするものです.もともとXMLにこのようなスタイルを指定することは御法度なのですが、

① 表紙のように一定の自由度や微調整が要求される出力対象で、オーサリング側にスタイルを記述することにより、いちいちスタイルシートを直さないで済む.またユーザー自身で調整が可能.
② 出力結果のレイアウトを少しでも校正したい場合、オーサリング側にスタイルを記述できるので、急を要するときやどうしても直したい場合に簡単に対応できる.

という場合に利用できます.「御法度」ですが結構便利なのです.もちろん再利用という観点からはあまり勧められませんが.

ところでこのXSL-FOの属性を記述するのにah-ditaではfo:propという属性を使用しています.DTDでこれをDITAのおよそすべての要素に指定できるようにするための作業は意外と大変なのです.DITAには属性も種類と階層があり、一般的には"Universal attribute group"が多くの要素に使用され、そしてそれはID attribute group, Metadata attribute groupLocalization attribute groupDebug attribute groupから構成されています.しかし必ずしもすべての要素が"Universal attribute group"を適用できる訳ではなく、個別に追って指定を付け加えねばなりません.これがDTDでやると結構大変なのです.こんな要素にスタイルを指定することはないだろうとも思いながらも、しかしDTDを直すとなるときっちりとやらねばなりません.このような作業は非常に孤独でテストも大変です.あまりやりたくありません.

で気が付いたのですが、実はこのような作業はまったくやる必要がなかったということです.それはDITAでの属性の特殊化には2種類あり、@propsか@baseから特殊化します.@propsは条件処理のプロパティです.@baseは特に目的を規定していない属性です.有名なEliot Kimberさんの特殊化チュートリアルでは、次のように紹介されていて、早飲み込みしててっきり属性の特殊化は条件処理のみと思いこんでいました.


Chapter 5. Attribute Specialization Tutorial
Goal: Declare an attribute domain vocabulary module that provides a new conditional (property) attribute.

You can specialize from the @base and @props attributes. For conditional processing (filtering and flagging), this lets you add your own attributes rather than using @otherprops, which can be clearer to authors and implementors.

For this tutorial, the goal is to declare an attribute domain module that provides a new conditional attribute, in this case the "phase of the moon" condition, useful for medical information for werewolves and other lycanthropes.

ところが@baseはfo:propの用途には最適なのです.ともかく条件処理ではなく、全ての要素を対象に考えているのですから.そこでRELAX NGで作成すると概略次のようになります.

<grammar 
  <define name="xslfoAtt-d-attribute">
    <optional>
      <attribute name="prop" ns="http://www.w3.org/1999/XSL/Format">
        <a:documentation>Specifies the XSL-FO property to which an element applies.
        </a:documentation>
      </attribute>
    </optional>    
  </define>
  
  <define name="base-attribute-extensions" combine="interleave">
    <ref name="xslfoAtt-d-attribute"/>
  </define>
</grammar>

属性定義はこれでおしまいです.あとはtopicなどのシェルにこのモジュールを取り込むのみです.RELAX NGではcombine="interleave"とやりさえすればnameで指定した定義に自動的に加わってくれるのでまったく世話がありません.

1.domains属性に、"a(base fo:prop)"を加え、この特殊化が含まれていることを示します.("fo:"が少し心配です.)
2.topicなどのシェルに上記のモジュールを<include href="~.xml"/>でインクルードします.

すべてはこれでおしまいです.いちいちすべての要素を追いかけまわして属性を追加するような必要はまったくありません.OASISの提供しているスキーマを修正する必要もまったくありません.RELAX NGはネームスペースをサポートしますが、DTDはネームスペースを理解できません.このためDTDに落とした場合、いくばくかは手作業で修正が必要になるでしょうが、それでもごく限られた範囲でしょう.

せっかくなのでOASISRELAX NGからXML Schema, DTDへのコンバーターを試してみましたが残念ながらXSLTでエラーでこけてしまいました.まだOASIS標準のものはOKでも特殊化を意図したスキーマは実績がないようです.

 oasis-open/dita-rng-converter

RELAX NGはDITA 1.3の公式のスキーマなので、早く特殊化したスキーマでも問題なくDTDXML Schemaへ変換できるようになってくれれば良いと思います.

しかし属性の特殊化で@propでなく@baseを使用している例は見たことがありませんでした.こんなところが気が付かなかった落とし穴です.