ENGLISHJAPANESE
<< リラックスのしかた/第一部: RELAX Core/STEP 8: tagとattPool再訪 >>

STEP 8: tagとattPool再訪


$Id: step8.sdoc 1.16 2000/11/01 14:58:13 murata Exp $
STEP 2では,tagが属性リスト宣言に相当し,attPoolが属性だけを定義するパラメータ実体に相当すると説明しました.実際には,より一般的な考え方がRELAXでは存在しています.

tag要素のrole属性

tag要素は,name属性のほかに,role属性を持つことができます.この節では,まずこの拡張の動機を説明し,つぎにrole属性を導入します.

属性によって異なる内容モデル

同じ名前のタグであっても属性の値によって内容モデルを変えたいということがしばしばあります.たとえば,valという要素のtype属性の値によってvalの内容モデルを変えたいとします.type="integer"と指定されていれば内容モデルはデータ型integerへの参照ですし,type="string"と指定されていればデータ型stringへの参照です.

<!-- This is legal. -->
<val type="integer">10</val>

<!-- This is also legal. -->
<val type="string">foo bar</val>

<!-- This is illegal. -->
<val type="integer">foo bar</val>

したがって,type属性の値がintegerstringかで,次の二つのelementRuleを使い分けたくなります.

<!-- Case 1: type="integer" -->
<elementRule role="val" type="integer"/>

<!-- Case 2: type="string" -->
<elementRule role="val" type="string"/>

しかし,STEP 7までの機能では,タグ名に対して内容モデルを記述しています.属性値は使われません.したがって,type属性の値に関わらず,同じelementRuleが適用されてしまいます.

tag要素が表す制約条件

tag要素は,name属性のほかに,role属性を持つことができます.tagの基本的な形は次の通りです.name属性はタグ名を指定しますが,role属性が指定するのは役割です.

<tag name="tag-name" role="role-name">
  ...
</tag>

tag要素は,タグ名と属性に関する制約条件の集まりを役割に関連づけます.tag要素に記述された条件を開始タグ(または空要素タグ)が満たすとき,このタグは指定された役割を持つと言います.
例として,次のtag要素を考えます.

<tag name="val" role="val-integer">
  <attribute name="type" type="NMTOKEN" required="true">
    <enumeration value="integer"/>
  </attribute>
</tag>

このtag要素は,「タグ名がvalであり,type属性の値はintegerという文字列である」という制約条件を表しています.この条件を満たす開始タグ(または空要素タグ)は,役割val-integerを持ちます.したがって,次の開始タグは,役割val-integerを持ちます.

<val type="integer">

次のtag要素では,type属性の値に関する条件が「値がstringという文字列である」に変わり,役割がval-stringに変わっています.

<tag name="val" role="val-string">
  <attribute name="type" type="NMTOKEN" required="true">
    <enumeration value="string"/>
  </attribute>
</tag>

次の開始タグは役割val-integerは持ちませんが,役割val-stringは持ちます.

<val type="string">

tag要素によって指定されていない属性があっても構いません.たとえば,次の開始タグの属性unknownは,先のtag要素で言及されていません.しかし,この開始タグは,役割val-stringを持ちます.ただし,診断メッセージは出力されます.

<val type="string" unknown="">

STEP 1から7までにあるようなrole属性がないtag要素はどう解釈されるのでしょうか.role属性がない場合は,name属性と同じものが指定されたものとみなされます.したがって次の二つのtag要素は同じ意味を持ちます.

<tag name="foo">
  <attribute name="bar" type="int"/>
</tag>

<tag name="foo" role="foo">
  <attribute name="bar" type="int"/>
</tag>

elementRule要素のrole属性

elementRule要素のrole属性は,タグ名を指定するのではなく役割を指定します.したがって,タグ名が同じであっても属性が違えば,別の生け垣モデルを使うことができます.
先の例で示した役割val-stringval-integerを使えば,タグ名がvalである開始タグに対して二つのelementRuleを使い分けることが出来ます.述語名val-stringを指定するelementRuleば,type属性の値がstringである開始タグを扱います.役割val-integerを指定すれば,type属性の値がintegerであるものを扱います.

<!-- Case 1: type="integer" -->

<tag name="val" role="val-integer">
  <attribute name="type" type="NMTOKEN" required="true">
    <enumeration value="integer"/>
  </attribute>
</tag>

<elementRule role="val-integer" label="val" type="integer"/>

<!-- Case 2: type="string" -->

<tag name="val" role="val-string">
  <attribute name="type" type="NMTOKEN" required="true">
    <enumeration value="string"/>
  </attribute>
</tag>

<elementRule role="val-string" label="val" type="string"/>

二つのtag要素がタグ名val"と属性名"typeを指定していることに注意して下さい.RELAXにおけるtag要素は,一度だけしか行われない宣言ではなく,何度でも書ける制約条件なのです.

ref要素による参照の禁止

ref要素が参照する役割を,tag要素で記述してはいけません.記述するのなら,attPool要素で記述する必要があります.
次の例にあるref要素は,tag要素によって記述された役割fooを参照しています.したがって,構文エラーです.

<tag name="foo"/>

<attPool role="bar">
  <ref role="foo"/>
</attPool>

データ型none再訪

STEP 3ではデータ型noneを導入しました.属性が指定された場合と指定されない場合とで異なる内容モデルを用いるときに,noneは有益です.
たとえば<div class="sec"><div>で内容モデルを変えることを考えます.前者を表現する役割divSecは次のように記述されます.

<tag name="div" role="divSec">
  <attribute name="class" type="string">
    <enumeration value="sec"/>
  </attribute>
</tag>

問題は<div>を表現する役割divWithoutClassをどう記述するかです.次のように記述したとします.

<tag name="div" role="divWithoutClass"/>

この記述では,<div class="sec">に対しても,divWithoutClassが成立してしまいます.宣言されていない属性があるというメッセージは出ますが,両方の役割を持つとみなされてしまいます.(1)
属性classを持たないということを陽に指定するには,データ型noneを用いて次のように書く必要があります.

<tag name="div" role="divWithoutClass">
  <attribute name="class" type="none"/>
</tag>

データ型noneに属する文字列は存在しないので,どんな値を属性classに指定しても役割divWithoutClassを持つことはありません.

  1. RELAXでは,宣言されていない属性があっても,役割が成立す ることにしています.こうしている理由は二つあります.一つは,宣言されて いない属性があっても処理を続行するというのが従来のXMLパーサの挙動であ ることです.もう一つは,HTMLでは宣言されていない属性を許していることで す.

attPool要素

attPool要素は,パラメタ実体のように単に展開されるものではありません.attPool要素は,tag要素とほとんど同等の概念です.

attPoolが表す制約条件

tag要素は,タグ名に関する制約条件と属性に関する制約条件の集まりに役割を関連付けるものでした.attPool要素もほとんど同じで,違いはタグ名に関する制約条件を指定できないことだけです.すなわち,属性に関する制限の集まりに役割を関連付けるものがattPool要素です.
つぎのattPoolを考えます.

<attPool role="info">
  <attribute name="class" required="true">
    <enumeration value="informative"/>
  </attribute>
</attPool>

このattPool要素は,「classという属性が指定されており,その値はinformativeという文字列である」という条件にinfoという役割を関連付けています.タグ名が何であっても構いません.このattPoolによって,次の空要素タグは役割infoを持ちます.

<some class="informative"/>

tag要素のときと同様に,宣言されていない属性があっても構いません.たとえば,次の開始タグに対して役割infoは成立します.

<some class="informative" unknown=""/>

elementRule要素による参照の禁止

elementRule要素のrole属性で指定する役割を,attPool要素で記述してはいけません.記述するのなら,tag要素で記述する必要があります.
次のelementRuleは役割infoを参照しています.役割infoattPool要素によって規定されています.したがって,この例は構文エラーです.

<attPool role="info"/>
<elementRule role="info" label="informative" type="emptyString"/>

複数のtagまたはattPool要素による役割の共有の禁止

複数のtagまたはattPool要素が,一つの役割を共有することはできません.
以下の例では,二つのtag要素が役割barを共有しています.したがって,構文エラーです.

<tag name="foo1" role="bar">
  <attribute name="a" type="string"/>
  ...
</tag>

<tag name="foo2" role="bar">
  <attribute name="b" type="string"/>
  ...
</tag>

以下の例では,役割とタグ名の両方を共有しています.これも構文エラーです.

<tag name="foo" role="foo">
  <attribute name="a" type="string"/>
  ...
</tag>

<tag name="foo" role="foo">
  <attribute name="b" type="string"/>
  ...
</tag>

role属性が省略され,name属性の値が使われたときも,共有は許されません.次の二つのtag要素は,上の二つのtag要素と同じ意味を持ちます.したがって,この例も構文エラーです.

<tag name="foo">
  <attribute name="a" type="string"/>
  ...
</tag>

<tag name="foo">
  <attribute name="b" type="string"/>
  ...
</tag>

つぎの例では,二つのattPool要素が役割barを共有しています.したがって,構文エラーです.

<attPool role="bar">
  <attribute name="a" type="string"/>
  ...
</attPool>

<attPool role="bar">
  <attribute name="b" type="string"/>
  ...
</attPool>

最後に,tag要素とattPool要素が役割barを共有した例を示します.これも,構文エラーです.

<attPool role="bar">
  <attribute name="a" type="string"/>
  ...
</attPool>

<tag role="bar" name="foo">
  <attribute name="b" type="string"/>
  ...
</tag>

まとめ

STEP 7までは,tag要素はタグ名と属性を宣言するものだと見なしてきました.本当は,タグ名に関する条件と属性に関する条件に役割を関連づけるのがtag要素です.これまでは,役割とタグ名は常に同じでしたが,必ずしもそうではありません.多くの場合にはラベルと役割とタグ名には一対一に対応しますが,一般的にはそうではありません.
タグ名,ラベル,役割を記述・参照する構文が何であるかを表にまとめておきます.
構文要素 タグ名/ラベル/役割の区別
elementRulerole属性 tagで記述された役割への参照
elementRulelabel属性 ラベルの記述
hedgeRulelabel属性 ラベルの記述
reflabel属性 elementRuleによって記述されたラベルへの参照
hedgeReflabel属性 hedgeRuleによって記述されたラベルへの参照
tagname属性 タグ名の記述
tagrole属性 役割の記述
attPoolrole属性 役割の記述
refrole属性 attPoolによって記述された役割への参照
次に,タグ名,ラベル,役割がXML文書で出現するかどうかを表にまとめておきます.
名前の種類 インスタンス中で RELAXモジュール中で
タグ名 出現する 節の一部として出現する
役割 出現しない 節の一部として出現する(役割の記述と参照)
ラベル 出現しない 生成規則の一部として出現する(ラベルの記述と参照)
属性の値によって内容モデルを変えることは,従来のDTDでは不可能でしたが,RELAXでは可能になりました.必要な拡張はrole属性だけです.RELAXの簡潔さ,強力さの現れといっていいでしょう.RELAX!

<< リラックスのしかた/第一部: RELAX Core/STEP 8: tagとattPool再訪 >>