第18回 属性のデフォルトにまつわる論点を理解する
XML 1.0は、1998年にW3Cから勧告として公開された。当然中身は英語で、しかもEBNFと呼ばれる式によって重要な部分が記述してある。この連載では、XML 1.0を深く理解するために、そのXML 1.0勧告の最新版「Extensible Markup Language (XML) 1.0 (Second Edition)」をだれでも分かるように、やさしく読み解きながら解説していくことを目指している。(編集局)
川俣 晶
株式会社ピーデー
2004/2/6
■属性値のデフォルトとは?
今回の主な内容 属性値のデフォルトとは? 属性のデフォルトをめぐる争点 属性のデフォルトの定義 属性のデフォルトの生成規則 3つの妥当性制約 妥当性制約:必須属性 妥当性制約:属性デフォルトの構文的な正しさ 妥当性制約:固定の属性デフォルト 属性のデフォルトの実例 |
前回は、3種類ある属性の型(文字列型・トークン化型・列挙型)の中で、最後に残された列挙型について読んだ。列挙型の特徴は、DTDにおいて、XML文書の内容を文字列レベルで強く拘束する数少ない機能の1つであるところだ。DTDでは、要素や属性の名前や記述できる場所については、厳しく制約する機能を持っているが、要素内容や属性の値として記述される文字列に関しては、特定の文字列の記述を強制する機能は多くない。しかし、この列挙型は具体的に、属性の値として「これとこれしか書いてはならない」という文字列を指定できる。そのため、属性リスト宣言の雰囲気も、列挙型を記述する場合のみ、かなり違うものになっていた。
さて今回は、「3.3.2 Attribute Defaults(3.3.2 属性のデフォルト)」を読んでいく。これは、属性の省略を許すか否か、省略した場合のデフォルト値をどうするかについて記述された部分である。属性のデフォルト値を活用すると、DTDを使った処理と使わない処理では結果が異なる状況が容易に発生することになる。これは、「貴族とボヘミアン」の問題などとも関係が深く、XMLをどのように進化させていくかについての論点の1つといえる。そのような難しい状況を正しく理解し、自分自身の決断を行うための予備知識として、今回説明する属性のデフォルトを読みこなしておく価値があるだろう。
編集注:この連載では、XML 1.0勧告であるW3Cの「Extensible Markup Language (XML) 1.0 (Second Edition)」(英語)を参照し、その日本語訳として、日本工業規格 JIS X 4159:2002(リンク先は該当規格の原案ですが、最終版とほぼ同等の内容です)を参照しています。本文中のピンクの地の部分は、XML 1.0勧告の原文を示しています。 |
属性のデフォルトは、XML界において2つの相いれない正義がぶつかりあう「貴族とボヘミアン」の問題に深くかかわるところである。
この問題での1つの争点は、スキーマを使って妥当性を検証した場合と、しない場合で処理結果が異なることを認めるか否かである。スキーマの役割とは、「XML文書があらかじめ用意されたスキーマに照らして正しいかを検証するものだ」、とするならスキーマ使用の有無で結果が変化してしまうのは好ましくない。この点だけに注目するなら、処理結果が必ず同じにならないことはトラブルのもとなので、許容すべきではないと考えられる(スキーマを使わない処理は一切認めないことで、処理結果を必ず同じにするという考え方もあるが、ここでは本筋から外れるので取り上げない)。
しかし、XMLという勧告は、結果が同じにならないことを許容する言語として生まれた。その事実を、これから読んでいく「3.3.2 Attribute Defaults(3.3.2 属性のデフォルト)」や、次の「3.3.3 Attribute-Value Normalization(3.3.3 属性値の正規化)」より読み取れる。そのように考えれば、処理結果が異なることを許容することがXMLの本来的に正当な態度と見ることができるし、それを許容しなければ、新しいスキーマ言語を生み出す際に、XML 1.0勧告で規定されたDTDとの互換性を維持できないことになる。
では、処理結果が異なることを許容する、という結論でよいのかというと、そうでもない。なぜなら、DTDは本来XMLの祖先といえるSGMLで生まれたものであり、SGMLには妥当性を検証しない(DTD/スキーマを使わない)処理が存在しないからだ。つまり、SGMLには処理結果が異なる状況はそもそも存在しなかったのである。そして、XMLはSGMLとの互換性を意図した設計になっており、多くの機能がその趣旨を満たすためにXMLに取り込まれている。ということは、処理結果が異なる仕様は必ずしも積極的に導入されたのではなく、ただ単にSGMLとの互換性を与えた結果として発生したにすぎないと見ることもできる。
ともあれ、ここは処理結果が異なることを許容するか否かについて結論を出すべき場ではない。確認してほしいのは、XML 1.0勧告は処理結果が異なる規定を行っているという具体的な事実である。DTDを使用して処理された場合とそうでない場合では、具体的にどのような点で異なる結果をもたらすのか。それを確認するのに、属性のデフォルトは最適な機能といえるだろう。
では読み始めよう。まず基本的な説明からである。
An attribute declaration provides information on whether the attribute's presence is required, and if not, how an XML processor should react if a declared attribute is absent in a document. |
属性宣言は、属性の指定が必須かどうかについての情報を与える、そして、必須でない場合には、文書内で属性が指定されていないとき、XMLプロセサがどう処理することが望ましいかという情報も与える。 |
この文章は2つのことをいっている。1つは、「属性の指定が必須かどうかについて」である。これは、ある要素型に対して、ある属性が付加されることを指定する場合に、それが必須であるか、それとも省略可能であるかを指定するものである。
例えば、XHTMLで画像を指定するimg要素には画像のURIを指定するsrc属性があるが、これは必須の属性である。表示すべき画像が不明のままではimg要素の存在意義がなくなるからである。しかし、画像の高さや幅を指定するheight属性や、width属性は必須とはいえない。画像を取得すれば、サイズはおのずと判明するので、指定されなくても動作は行える。また、動的に生成される画像データなど、事前にサイズが不明の場合もあるので、これらの属性を必須とすると、実用上大きな問題が起きる。そのような利用上の必要性から考えれば、属性が必須であるかどうかを選択可能にすることの意義が分かるだろう。
もう1つは、文書中で属性が指定されていないときに、XMLプロセッサはどう対処すべきかである。ここで、「どう処理することが望ましいか(should)」という表現に注意しておこう。ここでは、mustという言葉は用いられておらず、shouldが使われている。つまり、これは、必須の要件ではない。
さて、具体的にこれは何を意味しているのだろうか。「文書中で属性が指定されていないとき」とは、属性リスト宣言で宣言された属性があるにもかかわらず、それに対応する属性がXML文書中に記述されていないとき、ということである。そのような状況は、「(属性の指定が)必須でない場合」に発生し得るわけである。その場合、XMLプロセッサがどのように処理することが望ましいか、という情報を属性リスト宣言に記述できるのである。
それらの情報をどのように記述するかは、次の生成規則で与えられる(EBNFの詳細については、「第2回 XML勧告読解に必須のEBNF」を参照)。
Attribute Defaults
|
1つの生成規則に、3つの妥当性制約(VC)と、1つの整形式制約(WFC)が付いている。
この生成規則[60]DefaultDeclは、生成規則[53] AttDefから参照されている。これはさらに属性リスト宣言の生成規則である[52] AttlistDeclから参照されている。以下にこの2つを再掲しよう。
|
すでに解説済みなので思い出しながら見てほしいが、属性リスト宣言(AttlistDecl)は、<!ATTLISTで始まり、要素の名前を記述し、そして、要素定義(AttDef)を0回以上繰り返し記述する。そして、要素定義(AttDef)は、属性の名前(Name)、属性の型(AttType)、属性のデフォルト(DefaultDecl)の3つの組み合わせで成り立っている。これまで、属性の名前、属性の型について読んできたのだが、次がいよいよ最後の属性のデフォルトというわけである。
さて、具体的に生成規則[60]DefaultDeclの内容を読んでいこう。これは以下のいずれか1つであるということを表現している。
- '#REQUIRED'
- '#IMPLIED'
- (('#FIXED' S)? AttValue)
さらに、('#FIXED' S)が?によって選択可能であると表現されているので、これを2つのケースに分ければ、以下の4つのいずれかと読むことができる。
- '#REQUIRED'
- '#IMPLIED'
- (AttValue)
- ('#FIXED' S AttValue)
この4つの生成規則を順番に見ていこう。最初は、#REQUIREDという文字列を書かねばならず、2番目は、#IMPLIEDという文字列を書かねばならず、3番目は、生成規則[10] AttValueに適合する文字列を記述しなければならない。この生成規則は、属性を記述するために使うものとして、すでに解説済みである。例えば、<element attribute="value">の中の"value"に対応するものであるが、開始タグなどの内部だけでなく、このような属性リスト宣言からも参照されているわけである。最後は、#FIXEDという文字列を書き、空白文字を書き、生成規則[10] AttValueに適合する文字列を記述しなければならない。
これらが意味していることの詳細は、次の文章が説明している。
In an attribute declaration, #REQUIRED means that the attribute must always be provided, #IMPLIED that no default value is provided. [Definition: If the declaration is neither #REQUIRED nor #IMPLIED, then the AttValue value contains the declared default value; the #FIXED keyword states that the attribute must always have the default value. If a default value is declared, when an XML processor encounters an omitted attribute, it is to behave as though the attribute were present with the declared default value.] |
属性宣言において、#REQUIREDはその属性が必須であること、#IMPLIEDはデフォルト値がないことを意味する。[定義:宣言が#REQUIREDでも#IMPLIEDでもないときには、AttValueの値が、デフォルト値となり、そして#FIXEDキーワードは、その属性の値がデフォルト値と常に同一でなければならないことを示す。デフォルト値を宣言している場合、この属性が省略されているのを見つけたなら、宣言したデフォルト値が属性値に指定しているとして、XMLプロセサは振る舞うものとする。] |
この段落は3つの文章から成り立っている。最初の文章は通常の文章だが、2番目と3番目は、「属性のデフォルト」という用語を定義する文章となっている。
最初の文章の#REQUIREDは容易に理解できるだろう。属性の定義で、#REQUIREDというキーワードを書いておけば、その属性を記述しないXML文書はすべて妥当ではないと判定される。例えばXHTML 1.1のDTDでimg要素の属性リスト宣言では、以下のようにsrc属性が定義されている。
src %URI.datatype; #REQUIRED |
最後の#REQUIREDキーワードがあるために、XHTML 1.1でsrc属性を記述しないimg要素を含むXHTML文書は、すべて妥当ではないと見なされるわけである。
次の#IMPLIEDはデフォルト値がないと説明されているが、これだけでは少し分かりにくいだろう。実際には、属性は必須であるものと必須ではないものに分けられる。必須であるものは#REQUIREDキーワードを指定する。必須ではない属性は、#REQUIREDキーワード以外の書式を使って記述することになる。つまり、#IMPLIEDは、必須ではない属性でかつデフォルト値がない場合に記述するキーワードということになる。これを使った例を1つ見てみよう。同じXHTML 1.1のimg要素のheight属性である。
height %Length.datatype; #IMPLIED |
これは、最後の#IMPLIEDが示すとおり、デフォルト値はなく、省略可能であることを示している。つまり、<img src="http://foo/" width="640" />というように明示的に画像の幅を指定してもよいし、<img src="http://foo/" />というように明示しなくてもよい。明示しない場合は、デフォルト値はないので、特に特定の画像幅が指定されるわけではない。
さて、次に進もう。ここからは、属性のデフォルトという用語を定義する文章となっている。
まず、#FIXEDキーワードのことは忘れて、前半の文章に集中しよう。宣言が#REQUIREDでも#IMPLIEDでもないときとは、これらのキーワードを使わず、生成規則[10] AttValueに適合する属性のデフォルトを記述する。そのとき、生成規則[10] AttValueの値が、属性のデフォルト値となる。それを実例を通して確認してみよう。以下はXHTML 1.1のbutton要素のtype属性の宣言である。
type ( button | submit | reset ) 'submit' |
これは属性の列挙型を用いており、type属性の値は、button、submit、resetのいずれか1つであるという意図が表現されている。そして、最後に記述された'submit'が生成規則[10] AttValueに適合するものであり、これが属性のデフォルト値となる。つまり、button要素に、type属性を記述しなかった場合は、submitが指定されたものと見なすわけである。
ここで、属性の列挙型では引用符を付けず、デフォルト値は引用符を付けていることに注意してほしい。属性の列挙型では、値は必ず生成規則[7]Nmtokenを満たす名前トークンなので、値に空白文字を含まない。つまり空白文字が区切りであるか値の一部であるか混乱することはない。それに対して、デフォルト値はさまざまな型の属性に対して使われる可能性があるものなので、引用符による区切りが必須となっている。つまり、属性の型がCDATAの場合は、空白文字を含んだデフォルト値を記述することができ、それを区切りの空白文字と区別するために、引用符が必須となるわけである。
さて、次に#FIXEDキーワードが付いた場合について読んでみよう。生成規則[10] AttValueに適合する属性値の手前に#FIXEDキーワードが記述された場合、その値は必ず指定された属性値と同じでなければならない意図を示す。必ず同じ値を記述することしか許さない機能に何の意味があるのかと思うかもしれないが、これはバージョン番号などを記述するために使うと便利である。つまり、あるDTD/スキーマ内では必ず固定値が使われるが、兄弟姉妹関係にある似て非なるDTD/スキーマ内では違う値を使うというケースである。例えばXHTML 1.1では、以下のような属性の定義が含まれている。
version %FPI.datatype; #FIXED '%XHTML.version;' |
これはhtml要素のversion属性だが、パラメタ実体XHTML.versionの値は「-//W3C//DTD XHTML 1.1//EN」と定義されているので、これ以外の値を記述することはできない。しかし、仮にXHTML 1.2という言語(実在しない)をつくるとすれば、XHTML 1.2ではversion属性の値は「"-//W3C//DTD XHTML 1.2//EN"」に固定されるというDTDを記述することができる。これらを扱う応用プログラムは、この属性値を調べて、適用するDTD/スキーマを切り替えることができるだろう。もちろん、XHTML 1.2で記述された文書をXHTML 1.1のDTDを用いて妥当性を検証すると、妥当ではないという結果になるかもしれないが、これは適切な結果である。
余談ではあるが、一般的にはDTDを適切に選択する手段は文書型宣言として提供されており、属性値を調べて切り替えるような方法は取られていない。新しい世代のスキーマ言語でも、スキーマを指定するための標準化された方法が用意されていて、このような各言語の属性を調べるような方法はあまり使われないだろう。それでも、属性でバージョン番号を明示しておくと便利な場合があるので、応用分野によっては活用されている。
ちなみに、「#FIXEDキーワードが記述された場合、その値は必ず指定された属性値と同じでなければならない」と説明した。それを読んで、「必ず指定された属性値と同じでなければならない」ということは「#FIXEDキーワードを記述した属性は、省略できない」ということなのか、と思う人がいるかもしれない。しかし、これは省略できないという意図を示すものではなく、もし属性値を記述するなら、指定値と一致するものでなければならない、という意図を示すものである。省略することは可能である。
さて、文章はさらに続く。これは、実際にはXML文書に記述されていない属性がそこにあるかのように扱うという規定である。例えば、要素elementの属性attributeのデフォルト値がdefaultValueである場合に、
<element /> |
というXML文書を読み込んだときに、「要素elementの属性attributeの値を取得しようとしたら、XML文書には書かれていないdefaultValueという値が取得されるようにしなければならない」ということである。ただし、読み込まれなかったDTDに記述されたデフォルト値などは、取得できないのはいうまでもない。明確に書かれているわけではないが、それを実現するところまで要求しているわけではない。つまり、指定されたDTDを処理する範囲が異なると、処理結果が異なるという状況があり得るわけである。
さて、次は、3つの妥当性制約についてである。整形式制約も1つ付いているが、これはすでに「3.1 Start-Tags, End-Tags, and Empty-Element Tags(3.1 開始タグ、終了タグおよび空要素タグ)」で説明済みのものが参照されているので、ここに説明文はない。これは、「整形式制約:属性値に<を含まないこと」で、属性値内で直接的または間接的に参照する実体の置換テキストには、<を含んではならない、という内容である。
少し分かりにくい文章かもしれないが、例えば、要素elementに付く属性attributeが#REQUIREDキーワードによって必須であると指定されたとき、以下のようなXMLは妥当ではないということである。
1: <document> |
この例では、XML文書中に必須の属性が記述されているので、#REQUIREDキーワードの要求を満たしているから妥当であるという解釈ができるかもしれない。しかし、ここでの意図は、個々のelement要素のすべてについて、必須の属性の記述を要求することなので、そのような解釈は適切ではない。そのことが、この妥当性制約によって明示されている。ちなみに、以下のように記述すれば妥当なXML文書となる。
1: <document> |
Validity constraint: Attribute Default Legal The declared default value must meet the lexical constraints of the declared attribute type. |
妥当性制約:属性デフォルトの構文的な正しさ 宣言したデフォルト値は、宣言した属性型の構文的な制約を満たさなければならない。 |
lexical constraints(構文的な制約)とは、文字の並びが規定に適合していることを意味する。属性の型には、文字の並びが条件を満たすだけではなく、その文字列が何か別の条件を満たすことを要求しているものがある。例えばENTITY型の値は、DTDで宣言する解析対象外実体とマッチしている、という条件を満たさねばならない。しかし、属性のデフォルト値として指定する場合は、あくまで文字の並びだけで条件を満たすことのみ要求されているというわけである。
さて、JIS X 4159ではこの後に1つの文章が続いている。これは、XML 1.0 Second Editionの正誤表に含まれるE9 Clarificationに対応するものである。これは以下のような内容である。
Note that only the syntactic constraints of the type are required here; other constraints (e.g. that the value be the name of a declared unparsed entity, for an attribute of type ENTITY) may come into play if the declared default value is actually used (an element without a specification for this attribute occurs). |
型についての構文的な制約だけが要求されていることに注意、ほかの制約(例えばENTITY型の属性の値は、宣言された解析対象外実体の名前であること。)は、宣言されたデフォルト値が実際に使われたとき(この属性を指定しない要素が現れたとき。)に有効になる。 |
この文章は、構文以外の属性値の正しさを調べるタイミングを明確化している。つまり、属性リスト宣言を解析する時点では、構文以外の属性値の正しさはチェックされない。チェックされるのは、XML文書を解析しているときである。そして、この属性を記述しない要素が出現しなければチェックは行われない。つまり、必ずこの属性を記述している限り、デフォルト値がチェックされる状況は発生しない。チェックされるのは、このデフォルト値が使われる場合だけである。
これに関してはすでに説明したとおりであるが、EBNFで意図が明確に表現できないので、文章で明確化しているわけである。
最後に、実例がいくつか記述されている。
<!ATTLIST termdef id ID #REQUIRED name CDATA #IMPLIED> <!ATTLIST list type (bullets|ordered|glossary) "ordered"> <!ATTLIST form method CDATA #FIXED "POST"> |
最初の例は、#REQUIREDと#IMPLIEDを使ったもので、id属性は省略できないが、name属性は省略することができ、デフォルト値はない。
2番目の例は、デフォルト値となる属性値を記述したもので、type属性を省略すると、orderedという値のtype属性があるものとして処理される。
3番目は、#FIXEDを用いて、記述できる値が固定されていることを示したものである。method属性を省略すると、POSTという値のmethod属性があるかのように処理され、もしmethod属性を記述する場合はPOSTという値以外を記述することはできない。
◇
さて、以上で属性のデフォルトの説明は終わりである。次回は、「3.3.3 Attribute-Value Normalization(3.3.3 属性値の正規化)」についての説明に入る。属性値の正規化とは、XMLプロセッサがXML文書に書かれた属性の値を応用プログラムが扱いやすいように加工する手順である。つまり、属性の値は、記述されたとおりの文字列が応用プログラムに渡されるわけではない。このあたりの動作を正しく理解することで、属性がより的確に使えるようになるだろう。特に、通常のテキストと属性値の使い分け、挙動の違いについて、いくつかの正しい知識が得られるはずである。
連載 やさしく読む「XML 1.0勧告」 |
- QAフレームワーク:仕様ガイドラインが勧告に昇格 (2005/10/21)
データベースの急速なXML対応に後押しされてか、9月に入って「XQuery」や「XPath」に関係したドラフトが一気に11本も更新された - XML勧告を記述するXMLspecとは何か (2005/10/12)
「XML 1.0勧告」はXMLspec DTDで記述され、XSLTによって生成されている。これはXMLが本当に役立っている具体的な証である - 文字符号化方式にまつわるジレンマ (2005/9/13)
文字符号化方式(UTF-8、シフトJISなど)を自動検出するには、ニワトリと卵の関係にあるジレンマを解消する仕組みが必要となる - XMLキー管理仕様(XKMS 2.0)が勧告に昇格 (2005/8/16)
セキュリティ関連のXML仕様に進展あり。また、日本発の新しいXMLソフトウェアアーキテクチャ「xfy technology」の詳細も紹介する
|
|