属性追加の欲望(2)

既存のOASIS標準の要素に属性を追加する例がdita-usersで議論されていました.

Rethinking "Custom" Attribute Specialization

ここで紹介されている方法は

1. @baseを特殊化して汎用の属性を追加する.例えば@foo
2. @fooを特定の要素、例えばtable要素に適用する制約条件モジュールを作る.
3. シェルのモジュール(DTD)でこの制約条件モジュールを加える.

こうすれば「厳格に特殊化のルールに適合する」ものではないにせよ、勝手に属性を追加するような「道を外れた特殊化」をしないで済むということになります.

「厳格に」というのは属性の特殊化条件は次のように述べられているからです.以下の条件は確かに満たされてはいません.

2.5.3.5 Specialization rules for attributes

It is declared as a global attribute. Attribute specializations cannot be limited to specific element types.

ここで紹介されている1~3の方法はDTDを用いたものです.DTDによる制約条件モジュールを作るのは、実体定義は「一番最初に行われたものが有効」という決まり事にすべてがかかっていると思います.ですので、制約条件モジュールは、

<!-- Constraint: Not including @foo in base attribute extensions: -->
<!ENTITY % base-attribute-extensions
""
>

と定義してtableに@foo属性を追加すれば済みます.base-attribute-extensionsは@baseの特殊化の実体定義です.これを""で打ち消してしまいます.こうして制約条件モジュールをシェルモジュールの先頭でインクルードすれば@fooは汎用の属性ではなくせるからです.

これをRELAX NGでやったらどうなるのか考えてみました.RELAX NGの場合、@baseの特殊化はたぶん次のような記述になるのではないかと思います.

  <define name="fooAtt-d-attribute">
    <optional>
      <attribute name="foo">
        <a:documentation>Specifies the foo property to which an element applies.
        </a:documentation>
      </attribute>
    </optional>    
  </define>
  
  <define name="base-attribute-extensions" combine="interleave">
    <ref name="fooAtt-d-attribute"/>
  </define>

特徴は、base-attribute-extensionsを定義するときに一般的にはcombine="interleave"を指定することです.この指定によりどこか別のbase-attribute-extensionsの定義とor条件になります.でもすごく便利なこの機能は、逆にいったん定義したものを打ち消すということはできないように思えます.ということは、そもそもbase-attribute-extensionsにfooAtt-d-attributeを最初から加えずに定義し、さも(?)汎用属性の扱いをしながらたとえばtable要素に属性として加えるということになります.

でも不安はつきません.DITA 1.3ではRELAX NGで大本のスキーマを記述し、それをDTDXML Schemaに変換するという方法を取っています.上記のような方法では、はたしてまともに特殊化したRELAX NGDTDに落とせるのでしょうか?

DITA 1.3はまだまだこれからなので、いまいちわからないことだらけです.