第17回 属性の型、列挙型を理解する

XML 1.0は、1998年にW3Cから勧告として公開された。当然中身は英語で、しかもEBNFと呼ばれる式によって重要な部分が記述してある。この連載では、XML 1.0を深く理解するために、そのXML 1.0勧告の最新版「Extensible Markup Language (XML) 1.0 (Second Edition)」をだれでも分かるように、やさしく読み解きながら解説していくことを目指している。(編集局)

川俣 晶
株式会社ピーデー
2004/1/10



3つある属性の型の1つ、列挙型
今回の主な内容
3つある属性の型の1つ、列挙型
属性の列挙型
 列挙型の属性の定義
 列挙属性の型のEBNFによる生成規則
 生成規則:EnumeratedType(列挙型)
 生成規則:NotationType(記法型)
 生成規則:Enumeration(列挙)
 記法についての説明
 妥当性制約:記法属性
 妥当性制約:1つの要素型に1つの記法
 妥当性制約:空要素に記法なし
 妥当性制約:トークンの重複なし
 妥当性制約:列挙
 相互運用性のための付加

 前回の「属性の型、文字列型とトークン化型を理解する」では、「3.3.1 Attribute Types(3.3.1 属性の型)」について、文字列型・トークン化型・列挙型と3種類あるうちの、文字列型・トークン化型について解説した。属性の型は、DTDにおいては要素型とはまったく異なるもので、1から読み直さねばならない。しかし、これは多くの新しいXMLのスキーマ言語に継承されているので、ここでしっかり学んでおく価値がある。新しいスキーマ言語では、DTDとの互換性のために、今回説明する属性の型と互換のある型を導入している場合も多く、DTDでの型の定義を知っておくと、新しいスキーマ言語がよく分かるという効能もある。

 さて、今回は3種類の属性の型の中で、最後に残された列挙型について読んでいく。列挙型は2つに分類でき、定義も文字列型・トークン化型と比較して複雑である。また、列挙型の特徴は、DTDにおいてXML文書の内容を文字列レベルで強く拘束する数少ない機能の1つであるところだ。

 DTDでは、要素や属性の名前や記述できる場所については、厳しく制約する機能を持っている。しかし、要素内容や属性の値として記述される文字列に関しては、前回取り上げたNMTOKENのように文字種類を制約することはあっても、特定の文字列の記述を強制するような機能は多くない。しかし、列挙型は具体的に属性の値として、「これとこれしか書いてはならない」と文字列を指定できる。そのため、属性リスト宣言の雰囲気も、列挙型を記述する場合にはほかの型とかなり違うものになる。このあたりも、今回の見どころとして読み取っていただきたい。

編集注:この連載では、XML 1.0勧告であるW3Cの「Extensible Markup Language (XML) 1.0 (Second Edition)」(英語)を参照し、その日本語訳として、日本工業規格 JIS X 4159:2002(リンク先は該当規格の原案ですが、最終版とほぼ同等の内容です)を参照しています。本文中のピンクの地の部分は、XML 1.0勧告の原文を示しています。

属性の列挙型

 前回、XMLの属性の型は、文字列型・トークン化型・列挙型の3種類あることを読んだ。文字列型・トークン化型についてはすでに読んだが、ここからの説明は、残された列挙型に関するものである。

列挙型の属性の定義

 最初はEnumerated attributes (列挙型の属性)という言葉の定義である。

[Definition: Enumerated attributes can take one of a list of values provided in the declaration]. There are two kinds of enumerated types:

[定義:列挙型の属性は、宣言したいくつかの値の1つを取ることができる。]列挙型には、2種類ある:

 ここには2つの文章があるが、冒頭の文章のみがEnumerated attributes(列挙型の属性)という言葉の定義であり、後の文章は定義の一部ではない。冒頭の文章からは、2つのことが読み取れる。1つは、列挙型の属性の値は、あらかじめ宣言しておく必要があるということである。もう1つは、この定義を逆から解釈すると、あらかじめ宣言していない値を記述することはできない、ということである。例えば、「見積送付依頼」という属性の値として、「送る」「送らない」のどちらかだけを許す、という条件を記述したい場合、「送る」「送らない」という値をあらかじめ宣言しておく必要があるということである。そして、

  見積送付依頼="送る"
  見積送付依頼="送らない"

は許されるが、

  見積送付依頼="値引きしてくれる場合のみ送る"

というように宣言されていない値を記述した場合は、妥当なXML文書ではないと判定されることになる。

 後の文章は、異なる話題について書かれている(この後の話題に対する前振りといってもよい)。ここで述べられている2種類について、この後に記述されているわけだが、明りょうに英語や日本語で、2種類とは○○と××である、とは書かれていないが、EBNF的には記述されているので、それを見ていこう(EBNFの詳細については、「第2回 XML勧告読解に必須のEBNF」を参照)。

列挙属性の型のEBNFによる生成規則

 次は、Enumerated Attribute Types(列挙属性の型)のEBNFによる生成規則である。

Enumerated Attribute Types
[57]    EnumeratedType    ::=    NotationType | Enumeration
[58]    NotationType    ::=    'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')' [VC: Notation Attributes]
[VC: One Notation Per Element Type]
[VC: No Notation on Empty Element]
[59]    Enumeration    ::=    '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')' [VC: Enumeration]


生成規則:EnumeratedType(列挙型)

 さて、順番に読んでいこう。[57] EnumeratedTypeは、「列挙型には、2種類ある」という2種類をEBNF的に表現しているものである。つまり、EnumeratedType(列挙型)とは、NotationType(記法型)またはEnumeration(列挙)のどちらか、ということである。ここで、EnumeratedType(列挙型)とEnumeration(列挙)の違いは分かりにくいが、これは定義の関係上やむを得ない。

 EnumeratedType(列挙型)には、記法という制限を受けるものと、そのような制限を受けないものがある。記法という制限を受けないものがEnumeration(列挙)であるが、そのような制限を意識しない(記法型を使わない)利用者は、EnumeratedType(列挙型)と区別できないのは仕方ないだろう。

生成規則:NotationType(記法型)

 次は、[58] NotationType(記法型)である。記法とは、事実上XMLの世界では滅んだものなので、まじめに読まなくても問題ないだろう。ちなみに、記法(notation)の定義は「4.7 Notation Declarations(4.7 記法宣言)」に出てくる。そこでは

記法は、解析対象外実体の形式、記法属性を持つ要素の形式または処理命令の対象とする応用プログラムを特定する名前とする。

と書かれている。これを読んでも、記法とは何をするものか分かりにくいと思う。実は、記法が具体的に何であるか、厳密には筆者にも分からないところがある。XML勧告を読んでも分からなければSGMLを見てみるか、と思って「JIS X 4151 文書記述言語SGML」をパラパラと見てみたが、記法識別子、記法宣言、記法属性、記法名といった用語については説明があるが、記法という言葉そのものの説明は見当たらなかった。

 どうも、データ内容記法(data content notation)という用語の定義が、求める記法の意味を定めているように読めるが、それによると「要素のデータ内容またはデータ実体の応用依存の表現法であって、通常の文書文字集合の意味を拡張または変更を表す。」と定義されている。この説明でも、応用依存つまり使う側によっていくらでも変わりうるということで、具体的な使い道はイメージしにくい。取りあえず、記法については、「4.7 Notation Declarations(4.7 記法宣言)」であらためて取り上げるとして、ここでは「記法と呼ばれる名前を扱う」とだけ認識して先に進もう。

 NotationType(記法型)の定義は、文字列'NOTATION'の後に空白文字があり、'('があり、省略可能な空白文字があり、生成規則[5]Nameに沿った名前を記述し、省略可能な空白文字+記号'|'+省略可能な空白文字+生成規則[5]Nameに沿った名前を0回以上繰り返し、省略可能な空白文字があり、最後に記号')'で終わる。例えば、

NOTATION (a|b|c)

のように記述できる生成規則というわけである。属性リスト宣言全体で見ると、以下のように記述可能ということである。

<ATTLIST elementName attributeName NOTATION (a|b|c) #IMPLIED>

 ここで、生成規則[58] NotationTypeに出てくるNameが、「宣言したいくつかの値の1つを取ることができる」という説明の「値」に対応する。ほかの個所では、Nameは属性の名前に対応して、値に対応していない場合があるので、注意しておこう。例えば、属性は名前と値からなる(生成規則[41] Attribute)という場合に、生成規則[5]Nameは値ではなく名前に対応するものとして使われる。しかし、ここではNameは値に対応している。これは、属性の値がNameという生成規則によって、より狭い範囲に拘束されることを意味する。

生成規則:Enumeration(列挙)

 次に、生成規則[59] Enumeration(列挙)である。これは、[58] NotationType(記法型)と似ているが、2つの点で異なっていることに注意しよう。

 第1の相違は、キーワード'NOTATION'を記述しないことである。このキーワードが記述されていなければ、[58] NotationType(記法型)ではなく、[59] Enumerationであると判断できる。

 第2の相違は、値として記述できる文字列として、生成規則[5]Nameではなく、[7]Nmtokenが使われていることである。NameとNmtokenの違いは、この連載でもすでに取り上げているが、主な相違は最初の1文字に数字を記述できるか否かである。例えば、「2ndEdition」は生成規則[5]Nameには合致しないが、[7]Nmtokenには合致する。

 もう1つ、記法型の場合と異なり、利用方法についての制約が何もないことに注意を払っておこう。[59] Enumeration(列挙)は、あくまで文字列の正しさだけを指定するものであって、生成規則[7]Nmtokenの範囲内であれば、どんな値を指定してもよく、使い方や意味を制約されることはない。

 以下に、Enumeration(列挙)に適合する文字列の記述例を示す。

(a|b|c)

属性リスト宣言全体で見ると、以下のように記述可能ということである。

<ATTLIST elementName attributeName (a|b|c) #IMPLIED>

これらの生成規則に付与された妥当性制約は、この後に説明があるので、それに任せよう。

記法についての説明

 この後に、1つの文章が続いている。

A NOTATION attribute identifies a notation, declared in the DTD with associated system and/or public identifiers, to be used in interpreting the element to which the attribute is attached.

記法属性は、その属性が付与されている要素を解釈するのに使用する記法を特定し、記法は、DTD内で宣言され、システム識別子および/または公開識別子に関連付けられる。

 ここでは、記法についての説明が書かれているが、この内容は「4.7 Notation Declarations(4.7 記法宣言)」から引用した定義とは食い違っているように見える。しかし、実質的に語っていることは同じである。これについての説明は、「4.7 Notation Declarations(4.7 記法宣言)」までお待ちいただきたい。それから、ここの文は単なる説明文で、定義ではない。「4.7 Notation Declarations(4.7 記法宣言)」に記述された文章は定義である。「JIS X 4159」を読んでいると区別しにくいが、XML 1.0勧告では、後者に「Definition:」という文字列が付き、[……]でくくられることで、定義であることが示されている。この文章にはそのような記述は付加されていないので、定義ではないということである。

妥当性制約:記法属性

 次は、いよいよ妥当性制約についての説明である。

Validity constraint: Notation Attributes

Values of this type must match one of the notation names included in the declaration; all notation names in the declaration must be declared.

妥当性制約:記法属性

この型の値は、宣言に含まれるいくつかの記法の名前の1つとマッチしなければならない。つまり、宣言に含まれる記法名は、すべて宣言されていなければならない。

 最初は、Validity constraint: Notation Attributes(妥当性制約: 記法属性)である。文書は回りくどいが、要するに、名前は宣言されていなければならない、ということを示している。ここでいう宣言は、「4.7 Notation Declarations(4.7 記法宣言)」で定義される「記法宣言」によって行われる必要がある。

妥当性制約:1つの要素型に1つの記法

Validity constraint: One Notation Per Element Type

No element type may have more than one NOTATION attribute specified.

妥当性制約:1つの要素型に1つの記法

1つの要素型には、たかだか1つの記法属性しか指定できない。

 次は、Validity constraint: One Notation Per Element Type(妥当性制約: 1つの要素型に1つの記法)である。1つの要素型には1つの記法属性しか指定できない、というのは、ID型の属性の制約に似ている。ID型の属性は、個々の要素に固有の識別名を付けるために使われるので、1つの属性が複数の識別名を持つと問題が起きる、というわけで複数の識別名を持つことは禁止される。同様に、記法は個々の要素に、何らかの機能や役割を指定するものであるため、複数の記法を指定できると相矛盾してしまう可能性がある。そのため、複数の記法属性を指定することは許されない。

妥当性制約:空要素に記法なし

Validity constraint: No Notation on Empty Element

For compatibility, an attribute of type NOTATION must not be declared on an element declared EMPTY.

妥当性制約:空要素に記法なし

相互運用性のためにはNOTATION型の属性をEMPTYと宣言された要素に対して宣言してはならない。

 これは、Validity constraint: No Notation on Empty Element(妥当性制約: 空要素に記法なし)である。「相互運用性のためには」というのは、拘束力は持たない推奨事項である。「ISO 8879へのWebSGML適用附属書以前から存在するSGMLプロセッサが、XML文書を処理できる可能性を高めるために、これらの推奨事項を取り入れる」としたもので、そのような条件に対応するSGMLプロセッサを使う場合には、この妥当性制約を意識する価値がある。

 取りあえず、空要素には記法を使わないようにすれば問題はないが、そもそもXMLでは記法を使うことがほとんどないので、忘れ去っても実用上はあまり困らないだろう。

妥当性制約:トークンの重複なし

 次に、「JIS X 4159」には「妥当性制約:トークンの重複なし」が記述されている。しかし、これはXML 1.0 2nd Editionにはなく、正誤表のE2 Substantiveにあるもので、以下のような内容である。

Validity constraint: No duplicate tokens

The notation names in a single NotationType attribute declaration, as well as the NmTokens in a single Enumeration attribute declaration, must all be distinct.

妥当性制約:トークンの重複なし

単一のNotationType属性宣言における記法名は、すべて異なるものとする。同様に、単一のEnumeration属性宣言におけるすべてのNmtokenは、すべて異なるものとする。

 これは、(a|b|c|a)のような無意味な記述は間違いとする、ということを示している。この例の場合、a、b、c、aのうちのどれか1つを記述できるという意図を表現しているわけだが、最初のaが選択された場合と、最後のaが選択された場合には、意味的な違いは何もない。むしろ、トラブルのもとになりかねない。通常は、禁止されても問題のない制約であるといえる。

妥当性制約:列挙

Validity constraint: Enumeration

Values of this type must match one of the Nmtoken tokens in the declaration.

妥当性制約:列挙

この型の値は、宣言に含まれるいくつかのNmtokenトークンの1つとマッチしなければならない。

 これは、Validity constraint: Enumeration(妥当性制約: 列挙)である。多くの読者は何をいまさらと思うかもしれないが、列挙として記述した属性の値は、列挙として記述した値のどれかと一致しなければならない。例えば、(a|b|c)と宣言されていたら、属性値としてdを書くと妥当なXML文書ではなくなってしまうわけである。当然とも思えるこのような妥当性制約が付加されているのは、この意図がEBNFでうまく記述できないためである。

相互運用性のための付加

 以上で、妥当性制約の説明は終わりである。この後にもう1つの文章があって、これで長かった「3.3.1 Attribute Types(3.3.1 属性の型)」も終わりになる。

For interoperability, the same Nmtoken should not occur more than once in the enumerated attribute types of a single element type.

相互運用性のためには、同じNmtokenは、1つの要素型のいくつかの列挙型の属性として、複数回現れないことが望ましい。

 これは、Validity constraint: No duplicate tokens(妥当性制約:トークンの重複なし)と同じことを述べているようにも思える。しかし、よく読むと、対象が同じではないことが分かる。Validity constraint: No duplicate tokens(妥当性制約: トークンの重複なし)は、単一の属性宣言を対象としているが、この文章は、「1つの要素型のいくつかの列挙型の属性」が対象である。つまり、こちらの方が範囲が広い。

 次の疑問は、この文章が妥当性制約になっていないことである。これは、この文章がshould(望ましい)という言葉で、必須の強制制約となっていないためだと思われる。また、これには「相互運用性のため」という用語が付加されている。すでに説明したとおり、これは拘束力を持たない推奨事項である。

 この2つのことを併せて考えれば、必須の強制制約となっておらず、しかも拘束力は持たない推奨事項ということになる。事実上、あまり重要視する必要はないだろう。

 さて、以上で列挙型の説明は終わりである。次回は、「3.3.2 Attribute Defaults(3.3.2 属性のデフォルト)」の説明に入る。スキーマのレベルでデフォルト値を指定する、というのは、整形式ばかり使っているXML利用者には新鮮な話題かもしれない。しかし、手放しで喜べる機能というわけではない。整形式では扱えないということは、1つのXML文書を整形式で扱う場合と、妥当なXML文書として扱った場合で、処理結果が同じにならない可能性があるということである。これは、XMLの世界にある重要な対立の1つである興味深い話題にもつながっていく。次回を楽しみにお待ちいただきたい。

 

連載 やさしく読む「XML 1.0勧告」


XML & SOA フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

HTML5+UX 記事ランキング

本日月間