HTMLをはじめとするSGML (Standard Generalized Markup Language) の応用言語は、マークアップ記号によって文書の構成要素を示していきます。そのためには、どんなタイプの要素をどのような規則でマークアップするかを明確にしておかなければなりません。 このような、マークアップの構成要素、その順序(親子関係)、指定できる属性などについて定めた規則が文書型定義 (Document Type Definition: DTD) です。
DTDは様々な宣言を行っており、次に示す4つの宣言部から構成されています。
DTD(文書型定義)は、SGMLアプリケーションにおける文法書、あるいはテンプレートのようなものです。SGMLのいろいろな応用ごとにDTDが定義されます。
HTMLもSGMLの応用なので、HTML 4.01 TransitionalなどバージョンごとにDTDが定義されます。ここでは主としてHTML 4.01 (Strict)のDTDを例にとって書き方を説明します。
DTDは文書中に記述することも、外部ファイルに記述したものを指定して利用することもできます。HTMLの場合はW3C (World Wide Web Consortium) などで定義したものを外部DTDとして利用します。HTML(SGML)文書は、DOCTYPE宣言によって自らが基づくDTDを指定します。
外部ファイルに記述したものを指定して利用する場合は、外部サブセットのURIを指定します。DTDの拡張子には
.dtd
が使われることが多いです。
<!DOCTYPE root PUBLIC fpi uri [
declarations
]>
<!DOCTYPE root PUBLIC fpi uri>
<!DOCTYPE root PUBLIC fpi [
declarations
]>
<!DOCTYPE root PUBLIC fpi>
<!DOCTYPE root SYSTEM uri [
declarations
]>
<!DOCTYPE root SYSTEM uri>
ルート要素の名前を指定する。ルート要素名。HTMLでは大文字と小文字を区別しないので、ルート要素は「HTML」と「html」のどちらでもよい。XHTMLは大文字と小文字を区別するため、ルート要素はhtml
である。
公開されたDTD
プライベートDTD
公開識別子をFPI (Formal Public Identifier) 形式で指定する。
外部識別子。外部サブセットのURIを指定する。
内部サブセットを記述する。
文書中に記述する場合は、SGML文書で使う 要素タイプ (見出し、段落などの文書を構成する部品)について、どのような構造でどのように書くかを定義します。
<!DOCTYPE ルート要素名 [ 要素宣言 属性リスト宣言 実体宣言 記法宣言 ]>
HTMLのDTDは、W3Cが定義したものが公開されている。ただし、HTML5ではDTDは提供されなくなったため、公開識別子や外部識別子は存在しない。
<!DOCTYPE HTML>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
現在のWebブラウザの多くは、HTML文書やCSSをW3C標準仕様に準拠した解釈で表示する。しかし、過去のWebブラウザでは独自の解釈で表示していた。この独自解釈に合わせたために、W3C標準仕様に準拠していないWebサイトも数多く存在する。このため、WebブラウザにはW3C標準仕様の「標準モード(strict mode)」と、過去の遺物を表示するための「互換モード(quirks mode)」の2つのモードがある。文書タイプ宣言の「外部サブセットのURI」を指定するか否かによって、これらのモードを切り替えることができる。
種類 | 文書タイプ宣言 | モード |
---|---|---|
HTML5 | <!DOCTYPE html> |
標準 |
HTML 4.01 Strict | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> |
標準 |
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> |
互換 | |
HTML 4.01 Transitional | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> |
標準 |
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> |
互換 | |
HTML 4.01 Frameset | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd"> |
標準 |
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN"> |
互換 | |
- | なし | 互換 |
要素宣言では、要素タイプ名、開始タグと終了タグの省略の可否、内容モデルについて定義します。次に書式を示します。
<!ELEMENT 要素タイプ名 - - (内容モデル) >
要素タイプ名はHEAD、BODYなど(タグの名前としてお馴染みのもの)、次の「 - - 」はタグの省略についての決まり、 内容モデル (Content Model)は開始タグと終了タグに囲まれた部分に記述できる内容についての定義です。
タグの名前です。
左が開始タグ、右が終了タグについてで、 - が省略不可、 O が省略可(Omission)を表します。
例えば、HTML 4.01 StrictでP要素タイプの要素宣言は次のように定義されています。
<!ELEMENT P - O (%inline;)* >
開始タグは - なので必須、終了タグは O なので省略可能ということになります。
XHTMLのDTDの場合は、タグの省略についての記述はありません。XHTMLではタグの省略はできないからです。
別の場所で定義された要素タイプ名や実体名を使って、どんな内容がどんな順序で何回出現できるかを定義します。これによって要素の親子関係が決まります。出現順序や回数は次のような記号(演算子)で示します。
タイプ | 内容モデル | 意味 |
---|---|---|
接尾演算子 | A | 要素Aが1回だけ現れる |
A+ | 要素Aが1回以上出現する | |
A? | 要素Aが現れないか、1回出現 | |
A* | 要素Aが現れないか、任意回数出現 | |
接続演算子 | A | B | 要素Aもしくは要素Bのいずれか一方 |
A, B | 要素A及びBがこの順序で出現 | |
A & B | 要素A及びBが任意の順序で出現 | |
例外 | +(E) | 要素群(E)はその子孫にわたって出現して良い |
-(E) | 要素群(E)はその子孫にわたって出現してはいけない | |
その他 | ( ... ) | ...で示す要素をグループ化する |
EMPTY | 内容を持ってはならない | |
#PCDATA | 文字列 |
子要素が複数あるときは、カンマで区切って複数並べます。
<!ELEMENT 要素名 (子要素名1, 子要素名2, ...)>
<!DOCTYPE book [
<!ELEMENT book (title, author)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT author (#PCDATA)>
]>
<book>
<title>詳解UNIXプログラミング</title>
<author>W.スティーヴンス</author>
</book>
子要素の候補が複数あり、それらのいずれかである場合は、パイプ記号 '|' で区切って候補を並べます。
<!ELEMENT 要素名 (子要素名1 | 子要素名2 | ...)>
例えば、HTML 4.01 StrictでDL要素タイプの要素宣言は次のように定義されています。
<!ELEMENT DL - - (DT|DD)+>
これは開始タグ、終了タグとも必須で、内容としては DT 要素もしくは DD 要素が1回以上出現しなければならないということを意味しています。
+(E)
という書き方は、要素(群)Eは内容モデルの「例外」として出現して良いことを示します。この例外は「その要素の実現値の中の全ての場所に適用する」とされ、その子孫にわたって内容モデルにかかわらず出現して良いという意味になります。これは結果的にDTDの読み方を少し難しくしているので注意が必要です。例えばBODY要素タイプの定義を見てみましょう。
<!ELEMENT BODY O O (%block;|SCRIPT)+ +(INS|DEL) >
BODY要素の内容にはブロック要素 (
%block;
)もしくはSCRIPT要素が1回以上出現できます。 そして、例外として(ブロック要素でない)INS要素、DEL要素はBODYの直接の内容だけでなく、子孫要素全てに出現して良いことが示されています。INS,DEL要素タイプはBODY以外の内容モデルには直接登場しませんが、この例外が定義されている故に、BODY内のどこで使っても構わないわけです。個別の要素型宣言だけに注目していると見落としやすい点なので、注意してください。
子孫で出現できない例外としては、A要素タイプの宣言があります。
<!ELEMENT A - - (%inline;)* -(A) >
A要素の内容には他のインライン要素
(%inline;)
を記述できます。 インライン要素には A要素も含まれていますが、A要素の入れ子は例外として(子孫にわたって)禁止されています。
属性 (attributes)は要素が持つことのできるパラメータです。 IMG 要素タイプにおける SRC のように、それ無しでは要素が意味をなさないものもあれば、DL要素タイプのCOMPACTのように、オプションで用意されるものもあります。
<!ATTLIST 要素タイプ名
属性名 属性値 省略時値
属性名 属性値 省略時値
...
>
一つの要素タイプに対して属性は40まで定義できるので、「属性名 属性値 省略時値」のセットを連続して(行を分けるのが普通)記述して複数の属性を定義します。
詳細は複雑になるので割愛しますが、属性値としてよく使われる
CDATA
は文字データを、
NAME
は特別な約束に従った名前を、省略時値として使われる
#IMPLIED
は値はシステムが用意するので記述しなくても問題ない、
#REQUIRED
は省略せずに必ず記述という意味になります。
値 | 意味 |
---|---|
#IMPLIED | システムが用意するので記述しなくても問題ない |
#REQUIRED | 省略せずに必ず記述 |
META要素タイプの属性リスト宣言を見ると
<!ATTLIST META
%i18n; -- lang, dir, for use with content --
http-equiv NAME #IMPLIED -- HTTP response header name --
name NAME #IMPLIED -- metainformation name --
content CDATA #REQUIRED -- associated information --
scheme CDATA #IMPLIED -- select form of content --
>
となっていて、
%i18n;
というパラメータ実体で宣言されたものと、http-equiv, name, content, scheme
の4つを指定することができる
content
は必須で、それ以外は指定しなければシステムが既定値を用意する
http-equiv, name
はIDと同じ名前文字、content, scheme
は一般の文字(数字を含む)データ
ということが分かります。ちなみに各行の後半にある--で囲まれた部分はコメントです。
データ型 | 説明 |
---|---|
CDATA | 文字データ |
ID | 識別子 |
IDREF | 識別子参照 |
IDREFS | 複数のIDREFを半角スペースで区切って並べたもの |
NMTOKEN | 名前トークン |
NMTOKENS | 複数のNMTOKENを半角スペースで区切って並べたもの |
ENTITY | 実体参照 |
ENTITIES | 複数のENTITYを半角スペースで区切って並べたもの |
実体 (Entity)はDTDやHTML文書に頻繁に現れる要素などを別名として定義しておく、C言語のマクロあるいはエイリアスのようなものです。DTD内部だけで使うものをパラメータ実体と呼びます。
<!ENTITY 実体名 "置換実体文" >
DTD内部で参照するパラメータ実体の場合は、宣言において実体名の前に
%
を加え、参照時に
%実体名;
という形態をとります。たとえば、DTDのどこかで
<!ENTITY % heading "H1|H2|H3|H4|H5|H6">
という宣言をしておき、別のところで
<!ELEMENT (%heading;) - - (%inline;)*>
という要素宣言をすることで、見出し要素タイプについてまとめて定義することができるわけです(この場合、
%inline;
という実体についても別のところで宣言されている)。
なお、同じ実体宣言に
一般実体 というものもあり、ここで宣言されたものはHTMLの本文中で使うことができます。 たとえば、「
<
」と記述することで「
<
」を表すというのは、 HTMLのDTDにおいてこれが一般実体として宣言されているから利用できるわけです。