第9回 XML宣言と文書型宣言

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

川俣 晶
株式会社ピーデー
2003/5/2



基本的だが少々複雑
今回の主な内容
基本的だが少々複雑
Prolog and Document Type Declaration
XMLのバージョン番号
マーク付け機能の役割
妥当なXML文書とは
文書型宣言の出現位置
文書型宣言(document type declaration)
マーク付け宣言の定義

 今回は、XML 1.0勧告の中で、「2 Documents」(2 文書)の中の「2.8 Prolog and Document Type Declaration」(2.8 前書き及び文書型宣言)を解説する。

 「2 Documents」は、XML文書の基本的な構造について述べている部分である。その中で、「2.8 Prolog and Document Type Declaration」は、XML宣言や文書型宣言を扱っている部分だ。

 XML宣言や文書型宣言は、XML文書の基本的な構造を構成する重要な部分であり、かつ、少々複雑である。これらを省略してもXML文書は成立するが、省略されないで使われるケースが多いので、しっかりと把握しておく価値があるだろう。

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

Prolog and Document Type Declaration

 それでは、W3CのXML 1.0勧告の中から、「2.8 Prolog and Document Type Declaration」(前書き及び文書型宣言)を読み始めよう。ここは少々長い。EBNFの定義が12個。妥当性制約が2個。整形式制約が3個含まれている。ひとことで「前書きと文書型宣言」といっても、それに含まれている内容はそれだけ多いということである。気を引き締めていこう。

 さて、最初はXML宣言という言葉の定義(Definition)から始まる。

[Definition: XML documents should begin with an XML declaration which specifies the version of XML being used.] For example, the following is a complete XML document, well-formed but not valid:

<?xml version="1.0"?> <greeting>Hello, world!</greeting> 

and so is this:

<greeting>Hello, world!</greeting>

 まず、「XML文書はXML宣言で始めることが望ましく(should)、XML宣言は使用するXMLのバージョンを指定する」、としている。ここまでが定義(Definition)である。ここで分かることは、XML宣言の位置付けである。

 意外に思う方もいるかもしれないが、XML宣言は、文書がXMLのどのバージョンを使用して記述されているかを識別するために指定されるものであると位置付けられており、文字のエンコーディング情報を指定するためのものという位置付けではない。その理由はよく考えてみると分かるだろう。文字のエンコーディング情報は、XML文書に埋め込むほかにも、さまざまな指定方法が存在する。例えば、HTTPで送る場合は、HTTPヘッダーの中に「charset="UTF-8"」のような情報を含めることができるし、それはXML文書に含めるよりも好ましいやり方である。しかし、XMLのバージョン情報を明示する手段は、HTTPなどのプロトコル中には存在しない。これはXML文書の中で明示するしかないのである。

 続いて、「次に示す完全なXML文書は整形式であるが、妥当ではない」と書かれ、サンプルソースが続く。まずXML宣言を含む例があり、XML宣言を含まない例が続く。この2つの例は、どちらも整形式のXML文書として正しいことになる。これを見て分かるとおり、XML宣言で始めなくても間違いということではない。しかし、XML宣言は付ける方が「望ましい(should)」。

 XML宣言を付けないとどんな弊害があり得るのだろうか。すでに述べたように、エンコーディング情報はXML宣言以外でも指定する手段があり、XML宣言を付けないことが常に致命的な問題に直結するわけではない。しかし、XMLのバージョンの指定が欠落することが、何らかのトラブルを引き起こす可能性は考えられる。例えば将来のXMLが、名前に許す文字の種類を増やした場合(XML 1.1でそうなる可能性は高い)、そのバージョンでは正しいはずのXML文書に誤りがあると誤判定される可能性があり得る。逆に、XML 1.0で正しい構文の一部が、将来のXMLでは許されなくなる可能性もある。そうすると、XML 1.0で正しかった文書が正しくなくなる可能性もある。そのような場合でも、将来のXMLプロセッサが正しく処理してくれることを期待するなら、XML宣言を付けてバージョンを明示しておく価値があるだろう。

XMLのバージョン番号

 さて、次はバージョン番号の詳細についての説明である。

The version number "1.0" should be used to indicate conformance to this version of this specification; it is an error for a document to use the value "1.0" if it does not conform to this version of this specification. It is the intent of the XML working group to give later versions of this specification numbers other than "1.0", but this intent does not indicate a commitment to produce any future versions of XML, nor if any are produced, to use any particular numbering scheme. Since future versions are not ruled out, this construct is provided as a means to allow the possibility of automatic version recognition, should it become necessary. Processors may signal an error if they receive documents labeled with versions they do not support.

 まず、「この仕様のこの版に適合することを示すためには,バージョン番号“1.0”を使用しなければならない」としている。「この仕様」とはXMLのことで、「この版」とは1.0のことを示す。バージョン番号は文字列であることに注意が必要である。数値ではないため、1.0と1.00は等価ではないだろう(実際に、マイクロソフトのXMLパーサに掛けてみたら、「無効なバージョン番号です。」というエラーになった。さらに余談だが、“1.0”と“1.00”は、有効けた数を意識した場合には等価な数値ではない、ともいえる)。

 次に、「ある文書がこの仕様のこの版に適合しないとき、値“1.0”を使用するのは誤りとする」としている。

 次の文章は少し長い。「この仕様の今後の版に“1.0”以外の値を付与することがXMLワーキンググループの意図だが、XMLの将来の版を作成することを確約するわけではなく、作成したとしても番号付けについて特定の方法を使用することを確約するわけでもない」という。読んでそのとおりのことで、未来のことは何も保証しないことを明確にするために書かれたものである。

 次は、「将来のバージョンを作成する可能性があるので、必要な場合に自動的なバージョンの認識を可能とするためこの構文を提供する」としている。つまり、XML 1.0勧告は、このままで永遠不変ではなく、変化し得る可能性があることが、この仕様書の作成時点で認識されており、将来の変更に対する備えとしてバージョン番号を明記する手段が用意されているわけである。「automatic version recognition(自動的なバージョンの認識)」というキーワードについて注意を払う価値があるだろう。これは、プログラムが自動的にバージョンを認識することを主目的にしているものであり、コメントなどに「この文書はXMLのバージョンX用です」と書いても代用にならないことを意味している。

 最後に、「プロセサは、それがサポートしていない版番号の付いた文書を受け取ったなら誤りを通知してもよい」、としている。してもよい(may)であることから、バージョン番号の検査を行わずに何もエラーを出さずに、異なるバージョンのXML文書を処理してしまうXMLプロセッサが存在することは考えられる。

マーク付け機能の役割

 さて、この次の段落は、がらっと話題が変わって、文書型宣言についての説明に進む。

The function of the markup in an XML document is to describe its storage and logical structure and to associate attribute-value pairs with its logical structures. XML provides a mechanism, the document type declaration, to define constraints on the logical structure and to support the use of predefined storage units. [Definition: An XML document is valid if it has an associated document type declaration and if the document complies with the constraints expressed in it.]

 素直に順番に読んでいるといきなり面食らう。これまでの話題とは何のつながりもない説明が始まるのである。まず、「XML文書内のマーク付けの機能は、記憶構造(storage structure)および論理構造(logical structure)を記述すること、ならびに属性および属性値の対を論理構造に関連付けることにある」としている。これは、次の文章で文書型宣言について語る前ふりとなる文章であるが、理解できなくてもさほど問題はないだろう。この文章は難しすぎると思ったら読み飛ばそう。

 さて、次の文章では、「XMLは論理構造についての制約条件を定義するため、およびあらかじめ定義された記憶単位(storage units)を使用するための機構として文書型宣言(document type declaration)を提供する」とある。簡単にいえば、文書型宣言は、論理構造の制約条件と、定義済みの記憶構造を使用するためのものであるということだ。論理構造の制約条件とは、要するに要素や属性の種類や並び順の正しさに関するルールである。定義済みの記憶構造とは、すでに外部に存在する外部サブセットなどを意味すると思われる。これらを使うために文書型宣言が存在するわけである。

 なお、上記文中の「文書型宣言(document type declaration)」は略するとDTDと読める。しかし、一般的にXMLでDTDと呼ばれるのは、文書型定義(document type definition)の方である。この2つは、非常に似通っていて紛らわしいので注意が必要である。

妥当なXML文書とは

 次に進もう。次は妥当(valid)という言葉の定義である。「妥当なXML文書とは、文書型宣言を持ち、かつ(and)、その文書型宣言に示す制約条件を満たすXML文書とする」としている。「かつ(and)」である以上、両方の条件が成立しなければ妥当なXML文書ではない。しかし、文書型宣言を持っているが、それが指定する制約条件を満たさないXML文書があったとしても、整形式として正しいという可能性を残している表現である。

文書型宣言の出現位置

 次の段落は、文書型宣言の出現位置について記述した文章である。

The document type declaration must appear before the first element in the document.

 ここでは、「文書型宣言は、文書の最初の要素の前に現れなければならない」としている。これはEBNFでもより厳密に明示されている条件である。

 そしていよいよ、前書きに関するEBNF定義である(EBNFの詳細については、第2回「XML勧告読解に必須のEBNF」を参照)。

Prolog
[22]    prolog    ::=    XMLDecl? Misc* (doctypedecl Misc*)?
[23]    XMLDecl    ::=    '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
[24]    VersionInfo    ::=    S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"')/* */
[25]    Eq    ::=    S? '=' S?
[26]    VersionNum    ::=    ([a-zA-Z0-9_.:] | '-')+
[27]    Misc    ::=    Comment | PI | S

 順番に見ていこう。まず[22]prologは、[1]documentの定義、つまりXML文書の定義を行うEBNFから参照されている大事な定義だ。ちなみにXML文書は、

  document ::= prolog element Misc*

という定義になっている。elementがルート要素に相当するので、ルート要素の手前にあるものすべてがprologに該当するわけである。そのprologの定義が上記の[22]であり、

  prolog ::= XMLDecl? Misc* (doctypedecl Misc*)?

となっている。XMLDeclはXML宣言、Miscはコメント、空白、処理命令に当たる。そして、doctypedeclは文書型定義に当たる。これを見て分かるとおり、XMLDeclに?が付いているので、これは省略可能だ。doctypedeclに?は付いていないが、それを囲むカッコに付いているので、これも省略可能である。

 この括弧は、連続した無意味なMisc*を取り除くために意味がある。もし、括弧がないとすると、Misc* doctypedecl? Misc*のように記述することができるが、doctypedeclが省略されると、Misc* Misc*という定義を処理することになってしまう。その際、Miscに該当する何かが記述されている場合に、それが手前のMisc*に含まれるものか、後のMisc*に含まれるものかがあいまいになる。しかし、括弧を使って記述しているおかげで、そのようなあいまいさは生じない。doctypedeclが省略されるとき、その後のMisc*も同時に省略されるためである。

 次は、[23] XMLDeclつまりXML宣言である。これは

  XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'

という定義になっている。これを見て分かるとおり、<?とxmlは連続しており、間に空白文字などを入れることはできない。しかし、'?>'の手前に空白文字を意味するS?が記述されていることから、'?>'の手前に空白文字を挿入することは可能であることが分かる。また、バージョン情報を意味するVersionInfoは省略不可であるが、エンコーディング情報を記述するEncodingDeclと、非依存文書宣言を記述するSDDeclは省略可能であることも分かる。

 次は、[24] VersionInfoである。これはXML宣言中のバージョン情報について記述する部分である。定義は、

  VersionInfo ::= S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"')

となっている。ここで注意すべき点は、最初のSである。これに?記号が付いていないことから分かるとおり、この空白文字は省略できない。それから、引用符に'と"のどちらを使ってもよいことを示すために、"'" VersionNum "'"と'"' VersionNum '"'のどちらかという表現をしている。VersionNumが2回出てくるのが冗長のように思えるので、("'"|'"') VersionNum ("'"|'"')と書き換えたくなるが、それはできない。なぜなら、この定義にすると、"1.0'や'1.0"も許されてしまうからである。

 次は、[25] Eqである。これは、イコール記号を意味する定義である。単に'='と記述せず、独立した定義があるのは、前後に空白文字を入れることを許しているためである。

 次は、[26] VersionNumである。これは1.0という値でなければならないことが、すでに文章中で定められている。しかし、EBNFの方では、'1.0'とは書かれておらず、その代わり、

  VersionNum ::= ([a-zA-Z0-9_.:] | '-')+

と記述されている。これは、アルファベット大文字小文字と数字、そして、アンダースコア、ピリオド、コロン、マイナス記号のいずれかを1個以上繰り返すことを許す表記である。'-'だけが独立して記述されているが、これは[a-b]形式の表記では'-'記号が特別な意味を持つために分けて表記されているだけで、特別な役割を持っているわけではない。この表記のおかげで、実際には1.0のような数字+ピリオド+数字という組み合わせ以外の多彩な文字列が記述可能である。

 ここにあらゆる自由な文字を記述することを許していない、ということは、XML宣言を解析して、エンコーディング情報を取り出す処理の信頼性が上がる可能性が考えられる。ある種のエンコーディング方法では、通常のアルファベットなどと同じコードを異なる文字を表現するための情報として使う場合がある。例えば、シフトJISでは2バイト目にアルファベットと同じコードが入る場合があるし、まず使われる見込みはないがUTF-7でもアルファベットと同じコードを用いて漢字などを表現する場合がある。シフトJISで誤動作することがあるとは思えないが、何かの方法を使ったときに誤動作する可能性は考えられる。しかし、ここで使用できる文字を大幅に制限したことにより、US-ASCIIコードと互換性のあるエンコーディング方法を使っている限り、誤認識の潜在的な危険を減らせるかもしれない。

 次は[27] Miscである。これはComment | PI | S という定義になっていることから分かるとおり、コメント、処理命令、空白文字のいずれかを意味する。Miscが許された個所には、この3種類を入れることができる。注目すべき点は、このMiscが許される個所を見ることで、コメントや処理命令が許される箇所が明確に分かる点である。[22] prologを見ると、Misc*はXMLDecl?の後には書かれているが、先には書かれていない。つまり、XML宣言より前にコメント、処理命令、空白文字を書くことはできない、ということが分かるわけである。

文書型宣言(document type declaration)

 さて、次の段落はまるまる全体が文書型宣言(document type declaration)についての定義である。しかしすでにこの言葉は登場しており、定義される前に使われていたことになる。本当はあまりうれしいことではないが、XML 1.0勧告ではきちんと定義へのリンクが埋め込まれているので、読むときにはそれほど不自由はしないだろう。まあ、これはよしとして先に進もう。

[Definition: The XML document type declaration contains or points to markup declarations that provide a grammar for a class of documents. This grammar is known as a document type definition, or DTD. The document type declaration can point to an external subset (a special kind of external entity) containing markup declarations, or can contain the markup declarations directly in an internal subset, or can do both. The DTD for a document consists of both subsets taken together.]

 ここでは、「XMLの文書型宣言(document type declaration)は、ある文書クラス(class of documents)のための文法を記述するマーク付け宣言(markup declarations)を含むか参照する」としている。ここで気になるのは、「文書クラス(class of documents)」という言葉である。「文法(grammar)」も気になるが、これは既に登場している言葉である。それに対して、「文書クラス(class of documents)」はここにしか出現しない。ここでいうクラスとは、オブジェクト指向言語でいうクラスではない。もっと広義のある条件を満たす文書の集合であると考えるとよいだろう。では、どのような条件かというと、それが文法だといえる。文法の具体的な内容は、マーク付け宣言に記述されているわけである。そして、マーク付け宣言は、外部にある情報を参照する場合と、その内部に書き込んでしまう場合の2つがある、というわけだ。

 次に「この文法は、文書型定義(document type definition)またはDTDとして知られている」とある。文法イコールDTDと解釈してよいか少し悩むところである。一般的に、文法というものはDTDという具体的な構文で記述されるものよりは、もっと抽象的なものだと考えた方がよいように思う。抽象的な文法を表現する1つの具体的な手段がDTDであり、それとは別にRELAX NGやXML Schemaのような別の文法の表現手段があると考えた方が分かりやすいかもしれない。しかし、この文脈に限っていえば、文法を表現するものイコールDTDである。

 続いて「文書型宣言は、マーク付け宣言を含んだ外部サブセット(特別な種類の外部実体)を参照することができ、または内部サブセットにマーク付け宣言を直接含むこともでき、両方を使うこともできる」としている。「外部サブセット」「内部サブセット」「外部実体」は初めて出てくる言葉だ。

 この仕様書では、サブセット(subset)という言葉には特に定義は与えられていない。単純に、辞書を引いて出てくるとおり「部分集合」という理解でよいだろう。「外部サブセット」は「(文書型宣言の)外部の部分集合」、「内部サブセット」は「(文書型宣言の)内部の部分集合」と考えられる。つまり、この文章では、マーク付け宣言は外部にあっても内部にあっても両方にあってもよいとしている。内部も外部も部分集合という位置付けなので、両者を併せて使っても問題ないわけである。

 「外部実体」は後で定義が出現するが、ここでは「外部にある実体」と考えておけば間違いない。ここでは、外部サブセットは特別な種類の外部実体であるとしている。外部サブセットと外部実体は無関係な存在ではないということである。しかし、厳密に定義を追いかけていると、何か「外部実体」という定義があって、そのサブセットが外部サブセットの定義になっているわけではないことが分かる。「外部実体」にはEBNFによる定義はなく、概念的なものである。実際、どんな情報でも外部実体として参照できるので、包括的なすべての外部実体を扱う定義というものはあり得ないわけである。そこは注意して把握しなければならない。

 最後に、「ある文書のDTDは、両方のサブセットをまとめたものとして構成される」としている。つまり、外部サブセットと内部サブセットがあったとき、どちらか一方だけを使って他方を無視するのではなく、両方が使われるということだ。例えば、外部サブセットに要素の並び順のルールがあって、内部サブセットに実体の宣言があるなら、内部サブセットの実体を使用しながら外部サブセットに記述された並び順のルールによる妥当性検証ができるわけである。

マーク付け宣言の定義

 では次の段落に行こう。次の段落は、マーク付け宣言(markup declaration)についての定義を含んでいる。

[Definition: A markup declaration is an element type declaration, an attribute-list declaration, an entity declaration, or a notation declaration.] These declarations may be contained in whole or in part within parameter entities, as described in the well-formedness and validity constraints below. For further information, see 4 Physical Structures.

 最初の文はマーク付け宣言(markup declaration)の定義である。「マーク付け宣言は、要素型宣言、属性リスト宣言、実体宣言または記法宣言とする」としている。つまり、この4種類の宣言のいずれかということである。それぞれ後で詳しく取り上げられるので、ここでは説明を加えない。とはいえ、言葉を見ればその意味は何となく分かるだろう。

 次は、「下記に示す整形式制約および妥当性制約に規定するとおり、これらの宣言はパラメタ実体内に全体または一部が含まれてもよい」とある。「下記に示す」という部分は、今回の原稿には収まらず次回をお楽しみということになる。パラメタ実体はDTDで使用できる一種のマクロとして機能するものである。これらの宣言に関しては、パラメタ実体を自由に使って構わないということである。より詳しい情報は「4 Physical Structures」(4. 物理構造)を参照のこと、と書かれている。

 さて「2.8 Prolog and Document Type Declaration」(前書き及び文書型宣言)はまだ読み終わっていないが、今回はここまでである。次回は、この続きを解説する。

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


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

注目のテーマ

HTML5+UX 記事ランキング

本日月間