鳩丸よもやま話

bakera.jp > 鳩丸よもやま話 > 文書型宣言の読み方

文書型宣言の読み方

HTMLの骨組みと文書型宣言

まず、HTMLの骨組みについておさらいしてみましょう。HTML 4.01 で書かれたシンプルな HTML文書は以下のようになります。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/REC-html40/strict.dtd">
<HTML>
<HEAD>
<TITLE>ここにタイトルを書きます。</TITLE>
</HEAD>
<BODY>
<P>ここに本文を書きます。</P>
</BODY>
</HTML>

文書の先頭、<HTML> の前に記述されているものが、文書型宣言と呼ばれるものです (「DOCTYPE 宣言」と呼ばれることもあります。これは見たままですね)。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN"
"http://www.w3.org/TR/REC-html40/strict.dtd">

この記述を、順に検討してみましょう。

<!

文書型宣言は "<!" という文字列で始まります。<! はマーク宣言開始区切り子 (MDO) で、その名の通りマーク宣言の開始を意味します。文書型宣言もマーク宣言の一種ですから、MDO で始まります。

※ SGMLでは、他にも <!ENTITY……> や <!SGML……> などのマーク宣言が使われます。お馴染みの <!--コメント--> も「注釈宣言」というマーク宣言の一種です。

なお、MDO はあくまで、"<!" で一つの記号です。開始タグ開始区切り子 "<" に "!" がくっついているのではありません。当然、< と ! の間に空白を入れたりしてはいけません。

DOCTYPE

続く DOCTYPE は宣言の種類を表す予約名で、これが 文書型宣言であることを示しています。<! の後に空白を入れることは許されていません。ぴったりくっつけて半角で DOCTYPE と記す必要があります。

※HTML では小文字で doctype と書いても構いませんが、XML では DOCTYPE と大文字で書かなくてはなりません。

HTML

次に HTMLと書かれていますが、これは「文書型名」です。要するに当該文書のルートエレメント名を示しています。これによって文書全体が HTML 要素に属することになり、それゆえ <HTML> と </HTML> で括られることになるのです。

ここでたとえば <!DOCTYPE BODY …… などとすると、ルートエレメントは BODY になります。HEAD 要素のない、HTML文書ならぬ BODY文書? が宣言されることになるのです(もちろんそんなことをしてはいけません)。

PUBLIC

HTML の次に PUBLIC と書かれていますが、これは外部識別子です。外部に公開されている文書を参照し、その場所にそっくりそのまま貼り付けることになります。

<!DOCTYPE HTML [<!ELEMENT……>……]>とやってその場で DTD を記述する方法もあるのですが、各文書に巨大な DTD を記述するのは効率が悪いので、外部ファイルを参照するという方法が使われます。

"-//W3C//DTD HTML 4.0//EN"

PUBLICのうしろにある二重引用符の中身、これは参照する文書を特定する「公開識別子」です。HTML では SGML宣言で「FORMAL YES」と宣言されているので、特に「公的公開識別子」という物が用いられます。

公的公開識別子は、所有者識別子 ("-//W3C") 、区切り子 ("//") 、文識別子 ("DTD HTML 4.0//EN") 、という形になっています。

所有者識別子

所有者識別子は、その外部文書の所有者を表します。この場合、所有者は W3C です。 -// で始まるのは「未登録所有者識別子」で、この所有者が正式登録されていないことを示します。登録があると +// です。

文識別子

続く文識別子は、順に「公開文種別」("DTD")、「公開文記述」("HTML 4.0")、区切り子 ("//") 、公開文言語 ("EN"=英語) となっています。

この EN は参照先の文書型定義 (DTD) の言語を示しています。参照元の HTML文書の言語ではありません。これを勝手に JA に書き換えてしまう人がいるようですが、そんなことをしてはいけません。

※ちなみに、公開文種別や公開文言語の指定は大文字で行わなくてはならないとされています。

"http://www.w3.org/TR/REC-html40/strict.dtd"

最後に記述されているのは、システム識別子です。ここでは単に DTD の所在を示す URI となっています。

これは PUBLIC の公開識別子を補足するものなので、公開識別子だけで文書が識別できるならば省略しても構いません。逆に、システム識別子だけを使うことも出来ます。その場合は "PUBLIC" の代わりに "SYSTEM" を使って、

<!DOCTYPE HTML SYSTEM "http://www.w3.org/TR/REC-html40/strict.dtd">

のようにしますが、HTML の文書型宣言にはこの形は使われません。

※XML ではよく使われます。XHTML ではシステム識別子は必須です。

>

最後に > 。マーク宣言終了区切り子(MDC)で、宣言を閉じます。

SYSTEM 識別子は必要か?

末尾にはシステム識別子がくっついています。けれども、SGML的には PUBLIC と宣言して公開識別子を使っているのですから、システム識別子は省略可能です。現に HTML 3.2 以前ではシステム識別子はずっと省略されていました。

では、なぜこんなものがついているのでしょうか。HTML4.01 19.1 には以下のように書かれています。

If the document type declaration of your document includes a URI and your SGML parser supports this type of system identifier, it will get the DTD directly.

以上、HTML4.01 19 SGML reference information for HTML - 19.1 Document Validation より

要するに、システム識別子を解釈するパーサーが勝手に DTD をダウンロードしてきて文書を検証できるように、という親切心なのです。けれども皮肉なことに、この親切心で逆に誤動作してしまうパーサーも存在します。

仕様書にはシステム識別子を省略して良いとは書かれていませんが、SGML的には問題ありませんし、なにより仕様書自身のソースでは省略されているので、「省略できる」という解釈で問題ないでしょう。

近年では「システム識別子が省略されているか否か」を見て挙動を変えるブラウザがあるので注意が必要です。たとえば Microsoft Internet Explorer 6 は、HTML4.01 Transitional の文書型宣言に識別子がないと、互換性重視の「奇癖モード」で動作します。逆にシステム識別子があれば、HTML4 / CSS1 / CSS2 の仕様に比較的忠実な「標準モード」で動作します。「文書型宣言をつけたら挙動が変わった」などということが実際にあるので注意しましょう。

文書型宣言を忘れると?

基本的に、SGML文書には文書型宣言が必須です。これを省略することは出来ません。HTML も SGML応用系ですから、文書型宣言が絶対に必要です。

※XMLの場合は文書型宣言を要しないことがあります。

では、文書型宣言を書き忘れてしまうとどういうことになるのでしょうか。

RFC1866 には、以下のような記述がありました。

NOTE - If the body of a `text/html' message entity does not begin with a document type declaration, an HTML user agent should infer the above document type declaration.

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0 Level 2//EN">

以上、RFC1866 3.3. HTML Public Text Identifiers より

つまり、HTML2.0の時点では、「文書型宣言を省略すると HTML2.0 とみなす」というルールが確立していたのです。ですから、HTML2.0 に対応したブラウザは、文書型宣言のない文書を HTML2.0 とみなすでしょう。

※なお、HTML2.0 は "-//IETF//DTD HTML//EN" で、"-//IETF//DTD HTML 2.0 Level 2//EN" とは違うのではないか、と思う人もいるかもしれませんが、両者は同じ DTD を参照しています。

しかし、現在では少し事情が違います。HTML4.01 仕様書の附記B には、以下のような解説があります。

The HTML 2.0 specification ([RFC1866]) observes that many HTML 2.0 user agents assume that a document that does not begin with a document type declaration refers to the HTML 2.0 specification. As experience shows that this is a poor assumption, the current specification does not recommend this behavior.

以上、Appendix B: Performance, Implementation, and Design Notes - Notes on invalid documents より

HTML4 では、「HTML2.0 とみなすことは推奨しない」と言っています。これは HTML2.0 の記述を上書きしていると考えて良いでしょう。

では、文書型宣言のない文書がどう扱われるのか……と言われると、分かりません。「HTML2.0 とみなす必要はない」とは言っていますが、それ以上のことは何も言っていないのです。この解釈は仕様では定められていません。文書型宣言がない HTML 文書は HTML としても SGML としても不正で、そのエラー処理の方法は仕様では定められていませんから、ユーザエージェントの実装に依存することになります。

なお、XHTML の場合は明確で、文書型宣言がない場合は、単に well-formed な XML 文書となります。Valid ではありませんし、XHTML なのかどうかも分かりませんが、とりあえず XML として処理することは可能です。

良くある間違い

「HTML 文書は文書型宣言で始めなければならない」という解説は、厳密に言うと誤りです。文書型宣言はあらゆる要素の前になければならないのですが、文書型宣言の前には空白文字と注釈宣言、処理命令を書くことが出来ます。XML では XML宣言という処理命令が先頭に来るのが普通です。

HTML の場合は、余分なものを書かずに文書型宣言で始めた方がいいでしょう。

最近の日記

関わった本など