ENGLISHJAPANESE
<< リラックスのしかた/第一部: RELAX Core/STEP 2: XML DTDからの移行(パラメタ実体あり) >>

STEP 2: XML DTDからの移行(パラメタ実体あり)


$Id: step2.sdoc 1.10 2000/11/01 13:41:12 murata Exp $
STEP 2では,同じことを何度も繰り返して記述する代わりに,一回だけ記述しておいたものを繰り返して参照するための機構が加わります.XMLにあるパラメタ実体に相当します.

要素内容モデルの中で用いられるパラメタ実体

生け垣モデルを一回だけ記述し,それを繰り返して参照するための機構がhedgeRule 要素です.DTDにあるパラメタ実体のうち,内容モデルで使われるものに相当します.

概要

hedgeRule要素の構文を次に示します.fooはパラメタ実体の名前です.

<hedgeRule label="foo">
  ...element content model...
</hedgeRule>

このように定義したhedgeRuleを参照するには,<hedgeRef label="foo"/>と書きます.このhedgeRef要素は,hedgeRuleの中で指定された要素生け垣モデルで置き換えられます.
以下の例では,要素型docのためのelementRuleの生け垣モデルからhedgeRuleを参照しています.このelementRuleは,STEP 1の先頭にあるモジュールにあったものを書き換えて,title以外の部分をhedgeRuleで記述したものです.

<hedgeRule label="doc.body">
  <ref label="para" occurs="*"/>
</hedgeRule>

<elementRule role="doc">
  <sequence>
    <ref label="title"/>
    <hedgeRef label="doc.body"/>
  </sequence>
</elementRule>

doc.bodyへの参照は次のように展開されます.

<elementRule role="doc">
  <sequence>
    <ref label="title"/>
    <ref label="para" occurs="*"/>
  </sequence>
</elementRule>

この例では,elementRuleの中からhedgeRuleを参照しましたが,hedgeRuleの中からも同様に可能です.

使用できる生け垣モデル

hedgeRuleの中には,要素生け垣モデルだけが書けます.データ型参照や混在生け垣モデルは許されません.たとえば,以下の二つはどれも許されません.

<hedgeRule label="mixed.param">
  <mixed>
    <choice occurs="*">
      <ref label="em"/>
      <ref label="strong"/>
    <choice>
  </mixed>
</hedgeRule>

<hedgeRule label="string.param" type="string"/>

hedgeRefと混在生け垣モデルを併用するときは,hedgeRuleの中でmixedを使うのではなく,hedgeRefmixedで括ってelementRuleの中に書きます.その例を次に示します.混在生け垣モデルはphraseを参照しており,phrasehedgeRuleで記述されています.

<hedgeRule label="phrase">
  <choice>
    <ref label="em"/>
    <ref label="strong"/>
  <choice>
</hedgeRule>

<elementRule role="p">
  <mixed>
    <hedgeRef label="phrase" occurs="*"/>
  </mixed>
</elementRule>

occurs属性

hedgeRef要素はoccurs属性を持つことができますし,hedgeRuleの中に書かれる要素生け垣モデルもoccurs属性を持つことができます.次の例では,両方にoccurs属性が指定されています.

<hedgeRule label="bar">
  <sequence occurs="+" >
    <ref label="foo1"/>
    <ref label="foo2"/>
  </sequence>
</hedgeRule>

<elementRule role="foo">
  <hedgeRef label="bar" occurs="*"/>
</elementRule>

この例をDTDで表現すれば,パラメタ実体の展開がどう行われるべきかは明らかです.

<!ENTITY % bar "(foo1, foo2)+">
<!-- original --> <!ELEMENT foo (%bar;)*>
<!-- expanded --> <!ELEMENT foo ((foo1, foo2)+)*>

上の例を展開した結果を次に示します.展開のときに,一つしか子供を持たないchoice要素が導入されていることに注意して下さい.これは,hedgeRef要素にあったoccurs="*"を引き継いでいます.

<elementRule role="foo">
  <choice occurs="*">
    <sequence occurs="+" >
      <ref label="foo1"/>
      <ref label="foo2"/>
    </sequence>
  </choice>
</elementRule>

hedgeRefとhedgeRuleの 順番

DTDにあるパラメタ実体と違い,hedgeRefで参照する前にhedgeRuleを書く必要はありません.たとえば,次の記述はエラーではありません.

<elementRule role="doc">
  <sequence>
    <ref label="title"/>
    <hedgeRef label="doc.body"/>
  </sequence>
</elementRule>

<hedgeRule label="doc.body">
  <ref label="para" occurs="*"/>
</hedgeRule>

自分自身を参照しないこと

自分自身を直接または間接に参照するようなhedgeRuleを書いてはいけません.次の例では,barのための生け垣モデルの中でbarを参照していますからエラーになります.

<hedgeRule label="bar">
  <choice>
    <ref label="title"/>
    <hedgeRef label="bar" occurs="*"/>
  </choice>
</hedgeRule>

次の例では,bar1のための生け垣モデルの中でbar2を参照しており,bar2のための生け垣モデルの中でbar1を参照しています.したがって,エラーになります.

<hedgeRule label="bar1">
  <hedgeRef label="bar2" occurs="*"/>
</hedgeRule>

<hedgeRule label="bar2">
  <choice>
    <ref label="title"/>
    <hedgeRef label="bar1"/>
  </choice>
</hedgeRule>

emptyの用途

STEP 1で述べたemptyは,主にhedgeRuleの中で使います.以下に例を示します.

<hedgeRule label="frontMatter">
  <empty/>
</hedgeRule>

<elementRule role="section">
  <sequence>
    <ref label="title"/>
    <hedgeRef label="frontMatter"/>
    <ref label="para" occurs="*"/>
  </sequence>
</elementRule>

このモジュールを再利用する人は,frontMatterの記述をカスタマイズすることによって,sectionの構造を変更できます.

noneの用途

同じくSTEP 1で述べたnonehedgeRuleの中で使います.以下に,使用例を示します.

<hedgeRule label="local-block-class">
  <none/>
</hedgeRule>

<hedgeRule label="block-class">
  <choice>
    <ref label="para"/>
    <ref label="fig"/>  
    <hedgeRef label="local-black-class"/>  
  </choice>
</hedgeRule>

このモジュールを再利用する人は,local-block-classの記述をカスタマイズすることによって,block-classの内容を変更できます.

属性リスト宣言の中で用いられるパラメタ実体

属性宣言をいくつかまとめて一回だけ記述し,それを繰り返して参照するための機構がattPool要素です.DTDにあるパラメタ実体のうち,属性リスト宣言で使われるものに相当します.

概要

attPool要素の構文を下に示します.fooはパラメタ実体の名前です.

<attPool role="foo">
  ...attribute definitions...
</attPool>

このように定義したattPoolを参照するには,属性定義の並びの先頭に<ref role="foo"/> と書きます.このref要素は,attPoolの中で指定された属性定義の並びで置き換えられます.
以下の例では,要素型titleのためのtag要素からattPoolを参照しています.このtagは,STEP 1の先頭にあるモジュールにあったものを書き直したものです.多くの要素型に共通するrole属性が,common.attというattPoolに記述されています.

<attPool role="common.att">
  <attribute name="class" type="NMTOKEN"/>
</attPool>

<tag name="title">
  <ref role="common.att"/>
  <attribute name="number" required="true" type="integer"/>
</tag>

ref要素は次のように展開されます.

<tag name="title">
  <attribute name="class" type="NMTOKEN"/>
  <attribute name="number" required="true" type="integer"/>
</tag>

この例では,tagの中からattPoolを参照しましたが,attPoolの中からも同様に可能です.

refとattPoolの順番

refで参照する前にattPoolを書く必要はありません.たとえば,次の記述はエラーではありません.

<tag name="title">
  <ref role="common.att"/>
  <attribute name="number" required="true" type="integer"/>
</tag>

<attPool role="common.att">
  <attribute name="role" type="NMTOKEN"/>
</attPool>

複数のref要素

一つのtagまたはattPoolの中に,複数のref要素を書くことができます.以下に,一つのattPoolのなかで複数のref要素を用いた例を示します.必須の属性をcommon-req.attにまとめ,必須ではない属性をcommon-opt.attにまとめています.この二つをcommon.attを記述するattPoolから参照しています.

<attPool role="common.att">
  <ref role="common-req.att"/>
  <ref role="common-opt.att"/>
</attPool>

<attPool role="common-req.att">
  <attribute name="role" type="NMTOKEN" required="true"/>
</attPool>

<attPool role="common-opt.att">
  <attribute name="id" type="NMTOKEN"/>
</attPool>

自分自身を参照しないこと

hedgeRuleのときと同様に,自分自身を直接的または間接的に参照するのはエラーです.たとえば,次の例はエラーです.

<attPool role="bar1">
  <ref role="bar2"/>
  <attribute name="id" type="NMTOKEN"/>
</attPool>

<attPool role="bar2">
  <ref role="bar1"/>
</attPool>

まとめ

STEP 2までで,XMLのDTDで出来ることはだいたい出来ます.ぜひ使ってみて下さい.RELAX!

<< リラックスのしかた/第一部: RELAX Core/STEP 2: XML DTDからの移行(パラメタ実体あり) >>