ごくごく簡単なDTDの説明
DTD(文書型定義)は、SGMLアプリケーションにおける文法書、あるいはテンプレートのようなものです。SGMLのいろいろな応用ごとにDTDが定義されます。HTMLもSGMLの応用なので、バージョンごとにDTDが定義されます。ここでは主としてHTML 4.01 (Strict)のDTDを例にとって説明してみましょう。
DTDの役割
HTMLをはじめとするSGML (Standard Generalized Markup Language)の応用言語は、マークアップ記号によって文書の構成要素を示していきます。そのためには、どんなタイプの要素をどのような規則でマークアップするかを明確にしておかなければなりません。このような、マークアップの構成要素、その順序(親子関係)、指定できる属性などについて定めた規則がDTD (Document Type Definition) です。
DTDは文書中に記述することも、外部ファイルに記述したものを指定して利用することもできます。HTMLの場合はW3Cなどで定義したものを外部DTDとして利用します。HTML(SGML)文書は、DOCTYPE宣言によって自らが基づくDTDを指定します。
要素宣言
SGML文書で使う要素タイプ(見出し、段落などの文書を構成する部品)について、どのような構造でどのように書くかを定義します。記述方法は
<!ELEMENT 要素タイプ名 - - (内容モデル) >
という形です。要素タイプ名はHEAD、BODYなど(タグの名前としてお馴染みのもの)、次の「 - - 」はタグの省略についての決まり、内容モデル(Content Model)は開始タグと終了タグに囲まれた部分に記述できる内容についての定義です。
- タグの省略
左が開始タグ、右が終了タグについてで、 - が省略不可、 O が省略可(Omission)を表します。たとえばBODY要素タイプなどはここが「 O O 」になっているので、いずれも省略可能であり、P要素タイプのように「 - O 」になっているものは開始タグは必須で終了タグは省略可能ということになります(XHTMLに関する補足も参照)。
- 内容モデル
別の場所で定義された要素タイプ名や実体名を使って、どんな内容がどんな順序で何回出現できるかを定義します。これによって要素の親子関係が決まります。出現順序や回数は次のような記号(演算子)で示します。
DTDの内容モデルの表記方法 タイプ 内容モデル 意味 接尾演算子 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
文字列
例えば、辞書型定義リスト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要素の入れ子は例外として(子孫にわたって)禁止されているわけです。
〔補足〕 XMLではこの例外記述が採用されていないので、XHTMLのDTDでは、ins,del要素タイプは%misc;としてブロックレベル、インラインレベル両方に含まれるものとして定義され、a要素タイプは結構複雑な内容モデルとして示されています。
属性リスト宣言
属性(attributes)は要素が持つことのできるバラメータです。IMG要素タイプにおけるSRCのように、それ無しでは要素が意味をなさないものもあれば、DL要素タイプのCOMPACTのように、オプションで用意されるものもあります。基本的な記述法は
<!ATTLIST 要素タイプ名 属性名 属性値 省略時値orキーワード >
となります。一つの要素タイプに対して属性は40まで定義できるので、「属性名 属性値 省略時値」のセットを連続して(行を分けるのが普通)記述して複数の属性を定義します。
詳細は複雑になるので割愛しますが、属性値としてよく使われるCDATA
は文字データを、NAME
は特別な約束に従った名前を、省略時値として使われる#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
は一般の文字(数字を含む)データ
ということが分かります。ちなみに各行の後半にある--で囲まれた部分はコメントです。
実体宣言
実体(Entity)はDTDやHTML文書に頻繁に現れる要素などを別名として定義しておく、C言語のマクロあるいはエイリアスのようなものです。DTD内部だけで使うものをパラメータ実体と呼びます。記述法は
<!ENTITY 実体名 "置換実体文" >
となります。DTD内部で参照するパラメータ実体の場合は、宣言において実体名の前に%
を加え、参照時に%実体名;
という形態をとります。たとえば、DTDのどこかで
<!ENTITY % heading "H1|H2|H3|H4|H5|H6">
という宣言をしておき、別のところで
<!ELEMENT (%heading;) - - (%inline;)*>
という要素宣言をすることで、見出し要素タイプについてまとめて定義することができるわけです(この場合、%inline; という実体についても別のところで宣言されている)。
なお、同じ実体宣言に一般実体というものもあり、ここで宣言されたものはHTMLの本文中で使うことができます。たとえば、「<
」と記述することで「<
」を表すというのは、HTMLのDTDにおいてこれが一般実体として宣言されているから利用できるわけです。
要するに
お馴染みのタグはすべて要素宣言で定義されていますから、まず <!ELEMENT
で始まる部分に注目して、知りたいタグの名前を探すことです。そこではほとんどの場合、実体参照を使って内容が定義されますから、%実体名;
が出てきたら、それに対応する <!ENTITY % 実体名
という実体宣言を調べます。そこでも別の実体参照が使われている可能性があるので、理解できるまでその実体をさかのぼる必要があります。
せっかくDTDを読むのですから、内容モデルに注目しておきましょう。ここをきちんと把握すると、どの要素タイプ(タグ)の内部にはどの要素タイプ(タグ)を使っても良い、あるいは良くないという「要素タイプの親子関係に関するルール」が分かってきます。例えば、
H2
は %block; という実体のグループに属する要素タイプであり、
A
の内容モデルは
(%inline;)* -(A)
となっているから
<A name="foo"><H2>some heading text</H2></A>
という書き方は不適切であるということが分かってくるわけです。ね?
XHTMLに関する補足
XHTMLのDTDも基本的に同じものですが、これはXMLの実装としてXMLのDTDのルールに従うので、若干異なる部分があります。
XMLでは、タグの省略が認められません。また、要素タイプ名などは大文字と小文字が区別されます。そのため、HTMLで例に取り上げた「定義型リスト」要素タイプは
<!ELEMENT dl (dt|dd)+>
のようになっています。要素タイプ名が小文字になり、タグの省略に関する定義がなくなっていることが分かりますね。実際に、XHTMLを記述する場合は要素タイプ名、属性名ともに小文字を使う必要があり、終了タグは省略できません。また、hr要素タイプのように内容モデルを持たない(EMPTYである)ものは、
<hr />
という形で、開始タグを「 />」で閉じることになっています。
さらに、XHTMLは2001年5月に勧告となったXML Schemaを使って改めて定義されることになります。XML Schemaはそれ自体XMLで記述するので処理がしやすいほか、名前空間のサポート、データ型の厳密な定義など、DTDの弱点とされていた部分を補うことを狙いとしています。
なお、XHTML 1.1のDTDはモジュール化されているため、少々読み方が難しくなっています。ごくごく簡単なXHTML 1.1のDTDの説明を参照してください。