ENGLISH | JAPANESE |
$Id: step7.sdoc 1.13 2000/08/26 08:37:11 murata Exp $
STEP 6までのelementRule, hedgeRule
の説明は,DTDを知っている人がすぐに理解できる範囲だけを扱っています.実際にはもっと一般化された考え方がRELAXには存在しています.
elementRule
とラベルelementRule
は,label
属性
を持つことができます.ここでは,まずlabel
属性の目的を説明し,次に機構を説明します.
同じ名前のタグであっても出現位置によって内容モデルを変えたいということがしばしばあります.たとえば,章の中にある段落,表の中の段落は,どれも段落には違いありません.しかし,段落の中に許されるものは微妙に異なります.たとえば,章にある段落は脚注を含んでもかまいませんが,表の中の段落は文字だけに制限したいかもしれません.
<!-- This example is legal. --> <section> <para>This paragraph can contain footnotes <footnote>This is a footnote</footnote>.</para> </section>
<!-- This example is illegal. --> <table> ... <para>This paragraph cannot contain a footnote <footnote>This is an illegal footnote</footnote>.</para> ... </table>
したがって,段落が章の中にあるときと,表の中にあるときとでは,下記の二つの内容モデルを使いわけたくなります.
<!-- Case 1: subordinate to <section> elements. --> <!ELEMENT para (#PCDATA|footnote)*> <!-- Case 2: subordinate to <table> elements. --> <!ELEMENT para (#PCDATA)>
出現位置によって内容モデルを変えたいという例はHTMLにもあります.HTMLでは,a
要素が,他のa
要素の中に直接的または間接的に現れることを禁止しています.同様のことは,form
要素にもあてはまります.form
の中にform
が現れることは禁止されています.
<!-- This example is illegal. --> <a href="foo"><span><a href="bar">dmy</a></span></a>
<!-- This example is also illegal. --> <form> ... <div> <form> ... </form> </div> ... </form>
HTMLでは,a
要素はspan
要素を含むことができます.入れ子は間接的であっても禁止したいので,a
の外にあるspan
ではa
を許し,中にあるspan
では許さないようにする必要があります.form
についても同様で,form
の外にあるdiv
ではform
を許し,中にあるdiv
では許さないようにする必要があります.
<!-- Case 1: subordinate to <a> elements. --> <!ELEMENT span (#PCDATA|a)*> <!-- Case 2: not subordinate to <a> elements. --> <!ELEMENT span (#PCDATA)>
しかし,DTDでは,タグ名が同じである限り,内容モデルは常に一つです.したがって,段落の出現箇所によって,内容モデルを変えることはできません.span
の内容モデルも常に一つであり,span
がa
の中にあるかどうかで内容モデルを変えることはできません.div
の内容モデルも同様です.
この問題を回避するために,二つの方法が用いられてきました.一つの方法は,出現箇所ごとに別のタグ名を導入することです.この方法を用いた例を次に示します.章の中の段落にはparaInSection
というタグ名,表の中の段落はparaInTable
というタグ名を導入しています.
<!ELEMENT paraInSection (#PCDATA|footnote)*> <!ELEMENT paraInTable (#PCDATA)>
<!-- This example is legal. --> <section> <paraInSection>This paragraph can contain footnotes <footnote>This is a footnote</footnote>.</paraInSection> </section>
<table> ... <paraInTable>This paragraph cannot contain a footnote.</paraInTable> ... </table>
この方法には,DTDが大きくなると,ほとんど同じタグ名が急速に増えるという問題があります.段落,脚注,箇条書き等のような通常のタグ名が何倍にも増えるからです.
もう一つの方法は,タグ名は一つで済ませる代わりに,必要ないくつかの内容モデルをすべて足した内容モデルを作るというものです.この方法を用いた例を次に示します.章の中の段落だけではなく,表の中の段落にも,注釈が許されています.
<!ELEMENT para (#PCDATA|footnote)*>
この方法には,検証が不十分になるという問題があります.いまの例だと,以下の文書が検証を通ってしまいます.
<!-- This example is illegal. --> <table> ... <para>This paragraph cannot contain a footnote <footnote>This is an illegal footnote</footnote>.</para> ... </table>
elementRule
のlabel
属性同じタグ名が出現位置によって異なる生け垣モデルを持てるようにするため,RELAXはラベルを導入しています.タグ名が同じであってもラベルが違えば,異なる生け垣モデルが適用されます.
elementRule
はlabel
属性
を持つことができます.次に,elementRule
の基本的な形を示します.
<elementRule role="name" label="label"> ...content model... </elementRule>
label
属性が省略された場合は,role
属性と同じ値を指定したものと解釈されます.したがって,次の二つのelementRule
は等価です.
<elementRule role="foo"> ...content model... </elementRule>
<elementRule role="foo" label="foo"> ...content model... </elementRule>
脚注を含む段落と含まない段落とでラベルを使い分け,異なる内容モデルを指定した例を次に示します.
<elementRule role="para" label="paraWithFNotes"> <mixed> <ref label="footnote" occurs="*"/> </mixed> </elementRule> <elementRule role="para" label="paraWithoutFNotes"> <mixed> <empty/> <mixed/> </elementRule> <tag name="para"/>
一番目のelementRule
は,ラベルがparaWithFNotes
である段落の内容は脚注を含んだ文字列であることを示しています.二番目のelementRule
は,ラベルがparaWithoutFNotes
である段落の内容は単なる文字列であることを示しています.
多くの場合にラベルとタグ名は一対一に対応します.実際,STEP 6までの例ではそうでした.しかし,前節で示したような問題を扱うには,タグ名と一対一に対応しないラベルが必要になります.
ref
要素のlabel
属性
次に,ref
要素のlabel
属性を説明します.この属性の値は,常にラベルです.STEP 1では,値が要素型名だと書きましたが,あの説明は正確ではありません.RELAXには要素型という概念はありません.(実はXML 1.0にもありません.要素型宣言は定義されていますが,要素型の定義はどこを捜してもありません.)
前節の例にあるparaWithFNotes
とparaWithoutFNotes
はラベルですから,ref
要素から参照することができます.章のための内容モデルからは,paraWithFNotes
を参照します.表(正確には表のセル)のための内容モデルからは,paraWithoutFNotes
を参照します.
<elementRule role="section"> <ref label="paraWithFNotes" occurs="*"/> </elementRule> <elementRule role="cell"> <ref label="paraWithoutFNotes" occurs="*"/> </elementRule>
hedgeRule
複数のhedgeRule
がlabel
属性に同一のラベルを指定しても構いません.次の例では,ラベルblockElem
に対してhedgeRule
が二つ存在しています.
<hedgeRule label="blockElem"> <ref label="para"/> </hedgeRule> <hedgeRule label="blockElem"> <ref label="itemizedList"/> </hedgeRule>
次のelementRule
は,このblockElem
を参照しています.
<elementRule role="doc"> <sequence> <ref label="title"/> <hedgeRef label="blockElem" occurs="*"/> </sequence> </elementRule>
RELAX文法との照合のとき,hedgeRef
は最初にすべて展開されます.このhedgeRef
を例に展開の仕方を説明します.
ラベルblockElem
を記述する二つのhedgeRule
の生け垣モデルは,どちらもref
要素です.それらをまとめてchoice
要素で括った結果は次のようになります.
<choice> <ref label="para"/> <ref label="itemizedList"/> </choice>
展開したいhedgeRef
は,occurs
属性として*
を指定しています.このchoice
に,これを転記します.
<choice occurs="*"> <ref label="para"/> <ref label="itemizedList"/> </choice>
最後に,このchoice
要素でhedgeRef
を置き換えます.
<elementRule role="doc"> <sequence> <ref label="title"/> <choice occurs="*"> <ref label="para"/> <ref label="itemizedList"/> </choice> </sequence> </elementRule>
あるラベルを参照するhedgeRef
を展開するための手順をまとめておきます.
hedgeRule
をすべて探す.
hedgeRule
の生け垣モデルをchoice
要素で一つに括る.
hedgeRef
のoccurs
属性をこのchoice
要素に転記する.
choice
で,hedgeRef
を置き換える.
複数のhedgeRule
によるラベルの共有が認められているので,無理に一つのhedgeRule
にまとめる必要がありません.たとえば,numberedItemizedList
をblockElem
の一種として追加しても,次のhedgeRule
を書き足すだけで済みます.他のhedgeRule
を変更する必要はありません.
<hedgeRule label="blockElem"> <ref label="numberedItemizedList"/> </hedgeRule>
hedgeRule
とelementRule
によるラベル共有の禁止hedgeRule
とelementRule
が同じラベルを共有することは許されません.たとえば,次の例は構文エラーです.
<hedgeRule label="foo"> <ref label="bar"/> </hedgeRule> <elementRule role="foo" label="foo"> <empty/> </elementRule>
elementRule
複数のelementRule
がlabel
属性に同一のラベルを指定しても構いません.また,複数のelementRule
のrole
属性が同一であっても構いません.
以下の例では,二つのelementRule
がrole
属性としてsection
を指定しています.どちらもlabel
属性は省略されていますから,section
を指定しているものとみなされます.
<tag name="section"/> <elementRule role="section"> <ref label="para" occurs="*"/> </elementRule> <elementRule role="section"> <choice occurs="*"> <ref label="para"/> <ref label="fig"/> </choice> </elementRule>
ラベルを共有する複数のelementRule
が存在するときは,どれか一つが成立するだけで十分です.
次のsection
要素を考えます.一番目のelementRule
も二番目のelementRule
も,これを認めています.したがって,ラベルsection
を振ることができます.
<section><para/></section>
次のsection
要素はfig
要素を含んでいるので,二番目のelementRule
だけが成立しています.どれか一つが成立していれば十分ですから,やはりラベルsection
を振ることができます.
<section><para/><fig/><para/></section>
複数のelementRule
が同一のラベルを記述することの利点を説明します.すでにモジュールが作成されているとします.より広い範囲の文書が合法になるようにこのモジュールを変更することを考えます.
従来の方法では,既存のelementRule
を変更する必要があります.今まで合法だった文書が,この変更後にも合法であるという保証はありません.
RELAXでは,既存のelementRule
を変更せず,新たにelementRule
を追加することで対処できます.この方法だと,今まで合法だった文書がやはり合法であることは原理的に保証されています.
先の例では,para
だけをsection
の内容として許すのが当初の予定であり,一番目のelementRule
はそのために書かれています.その後に,fig
も内容として許すように二番目のelementRule
を追加しています.一番目のelementRule
は依然として有効ですから,今まで合法だった文書が合法でなくなることはありません.
いままで大規模なDTDを書くのに苦労してきた人には,STEP 7は魅力的に映ると思います.必ず問題になる部分がRELAXでは綺麗に書けます.RELAX!