DITA 1.2 + XML Schemaの幻想

昨年DITA Europe 2104に参加させていただきましたが、Eliot Kimberさんのセッションで「スキーマとして何を使っているか?」という聴取者への質問があって、みんなが該当のものに手を挙げてもらう機会がありました.結果はやはりDTDが大部分で、XML Schemaを使用している方に挙手した方はごくわずかでした.私もDTDを使用している方に手を挙げました.

実際のところDITA 1.3からはRELAX NGがスタンダードになるのですが、現時点で、つまりDITA 1.2でXML Schemaを使ってみたところどうなのか?という選択に迫られたことがあります.考えていても決まらないので、実際にやってみました.結果はちょっとがっかりしたものでした、はっきり言ってDITA 1.2 + XML Schemaへの「幻想」があったら捨てた方が良いのではないのかというのが感想です.

では何故XML Schemaを試してみようかと考えたのにはいくつかの理由があります.

1. DTDによる特殊化に疲れ果てた.幾度「DTD地獄」を味わったかわからない.
2. XML SchemaDTDと違ってXMLで記述するし、DTDでやたら出てくる実体定義の手間もいらない.
3. XML Schemaは難解と言われているが高機能で特殊化のための期待に応えてくれそう.

ちょっとミーハーな理由もありますが、「XML SchameならDTDよりはなんとかなるんじゃないのか?」というのが正直なところです.

「どのスキーマを使うか?」というのは「どのスキーマを使ってOASISのモデルを特殊化するか?」と同義語です.つまりOASISボキャブラリを自分用に直したり、追加したりして使用する訳です.XML Schameではこのようなことをする上でxs:redefineというスキーマの再定義の機能を使用しますが、これが非常に大事な役割を果たします.

xs:redefineを使用すると次のようなことはいとも簡単にできます.

・ある要素の属性を追加します.
・ある要素のコンテンツモデルの前後に新たな要素モデルを加えます.

例えば次のコーディングは、conceptとconbodyにfo:style-attsを加えます.

   <xs:import schemaLocation="ah_fo_style.xsd" namespace="http://www.w3.org/1999/XSL/Format"/>
   <xs:redefine schemaLocation="urn:oasis:names:tc:dita:xsd:conceptMod.xsd:1.2">
     <xs:attributeGroup name="concept.attributes">
       <xs:attributeGroup ref="concept.attributes"/>
       <xs:attributeGroup ref="fo:style-atts"/>
     </xs:attributeGroup>
   </xs:redefine>

xs:redefineの中でxs:attributeGroupは「自分自身を最初に参照」し、次に加える属性グループへの参照を書いてやれば良いのです.超簡単です.
ちなみにfo:style-attsは別ファイルで次のように定義されているものとします.

[ah_fo_style.xsd]
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
    elementFormDefault="qualified"
    attributeFormDefault="qualified"
    targetNamespace="http://www.w3.org/1999/XSL/Format">
    <xs:attributeGroup name="style-atts">
        <xs:attribute name="prop" type="xs:string"/>
    </xs:attributeGroup>
</xs:schema>

ネームスペースをサポートするXML Schemaでは、異なるネームスペースに属する定義は別ファイルにして、xs:importしなければなりません.

また要素の挿入も簡単です.元のスキーマで例えばfiggroupが次のように定義されていて、この前後にdesc要素を加えたければ

<xs:group name="figgroup.content">
<xs:sequence>
<xs:sequence>
<xs:group ref="title" minOccurs="0"/>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:group ref="figgroup"/>
<xs:group ref="basic.ph"/>
<xs:group ref="basic.block.notbnofg"/>
<xs:group ref="fn"/>
<xs:group ref="data.elements.incl"/>
<xs:group ref="foreign.unknown.incl"/>
</xs:choice>
</xs:sequence>
</xs:sequence>
</xs:group>

次のように書いてやれば良いだけです.

<xs:redefine schemaLocation="urn:oasis:names:tc:dita:xsd:commonElementMod.xsd:1.2">
<!--後に挿入したい場合-->
<xs:group name="figgroup.content">
<xs:sequence>
<xs:sequence>
<xs:group ref="figgroup.content"/>
<xs:group ref="desc" minOccurs="0"/>
</xs:sequence>
</xs:sequence>
</xs:group>
<!--前に挿入したい場合-->
<xs:group name="figgroup.content">
<xs:sequence>
<xs:sequence>
<xs:group ref="desc" minOccurs="0"/>
<xs:group ref="figgroup.content"/>
</xs:sequence>
</xs:sequence>
</xs:group>
</xs:redefine>

「ああなんと簡単か!」と思ったのですが感激したのはそこまででした.(以下続く)