HTMLのDTDを読んでみよう

HTMLには厳密な文法規則はない――これは大きな誤解です。特 定のウェブブラウザで綺麗に表示されているからといってそのHTML 文書が正しくタグ付けされているとは限りません。正しくないHTML 文書は別のブラウザで見るとおかしな表示になってしまうことがあ ります。しかし規則に従って適切にタグ付けされた文書はどんなブ ラウザで見ても読みやすく表示されるのです。少なくともブラウザ はそう作られているべきです。

HTMLはSGMLの応用の一つとして定義されていますから、 HTMLのタグ付けの規則について疑問があればDTD (後述)を参照するのが 一番確実です。DTDを読むにはSGMLの知識が必要ですが、 自分でDTDを書くとかならともかく、HTMLの決まりを確かめたくてDTDを 見るだけであればSGMLの全てを知っている必要はありません。この文章では HTMLについてある程度知っている読者を対象に、HTMLのDTDを読むのに 必要な最低限(に達しているだろうか?)の知識を提供します。

このページは、詳しいことはさておきとりあえずDTDを読んでみようという 趣旨なので、SGMLに関する事柄はあまり体系的にはまとめられていません。 詳しくは、巻末に掲げた参考文献を お読みになることをお勧めします。


目次:


第1章 SGMLの基本を知る―― HTMLを正しく理解するために

1.1 SGMLとは何か

SGMLは、文書の構造を記述し、文書を構成する要素(element)を マーク付け(markup)によって明示する言語です。ただし、言語といっても プログラミング言語ではありません。SGML文書は(ひいてはHTML文書も) プログラムではありませんし、タグ(後述)は命令ではありません。

SGMLのマーク付けは次のようなやり方でなされます。

上の特徴からSGML文書は特定の計算機環境にとらわれることなく自由に 交換できることがわかるでしょう。文書の構造が明示されているために 他のデータ形式への変換も容易であり、 文書のデータベース的な活用も可能にしています。 このような特徴は同じ構造を持つ文書を数多く扱う場合に特に有利であり、 そのため、大量のマニュアルを管理・運用しなければならない製造業界等で SGMLが採用されていることがあります。

SGML文書のマーク付けには主にタグというものを使います。 これはHTMLでよく知られているように、 <title>といった風に名前を不等号で括った形をしています(後述の SGML宣言によって不等号以外の記号を使うことも可能)。このタグに よって、「ここは見出し」「ここは段落」というように文書中の要素を明示 します。タグ付けの規則は後述のDTDによって定められます。

ワープロやTeX等とは違い、SGMLは文書の体裁に関する情報は持ちません。 SGML文書を印刷するには、SGMLとは別の形でスタイル情報を与える必要があります。 また、SGMLの(ひいてはHTMLの)処理系といえる物はDTDに従って文書を解析する パーザ(parser, パーサとも読む)であり、整形プログラムではありません。

なお、SGMLは1986年にISO 8879としてISO規格化され、1992年にはJIS X 4151 としてJISにもなっています。 SGMLという名前はStandard Generalized Markup Languageの略とされ、 日本語では標準汎用マーク付け言語などと訳されます。

1.2 SGML文書の3部構成: SGML宣言、DTD、文書インスタンス

SGMLの文書は、SGML宣言(SGML Declaration)、DTD (Document Type Definition, 文書型定義)、文書インスタンス(Document Instance)の3部から なり、文書中にこの順に現れます。この3つを逆順に簡単に解説します。

文書インスタンス
マーク付けされた文書そのものです。 HTMLでいうと<html>ではじまるHTML文書がこれに相当します。
DTD
文書の構造を定義します。HTMLでは、例えば段落は<p>で 表すとか、大見出しを<h1>で表すとかいうことが決められていますが、 SGMLではこのような決まりをDTDによって定義するのです。 タグ付けの規則を決めていると言ってもいいでしょう。SGMLの利用者は 文書の構造に応じて適切なDTDを(ときには自分で書いて)使うわけです。 SGMLの応用の一つたるHTMLの文書構造もやはりDTDによって定義されています。

その定義の内容は、文書中にどのような要素がどのような順番で現れるか (HTMLであればHEADの後にBODYが現れる、など)、 要素同士の包含関係はどうなっているか、各要素がどのような属性 (attribute)を持つか、などです。

オブジェクト指向風に考えて、 文書インスタンスに対してDTDは文書の「クラス」だと思ってもよいでしょう。

SGML宣言
文字セットの指定など、そのSGML文書自体の情報が 書かれます。通常はあまり気にしなくても構わないでしょう。

使用するDTDを指定するにはDOCTYPE宣言を書きます。 下の例(これはHTML 2.0の場合)のように<!DOCTYPE ... >と書きます。 ちなみにHTML 3.2ではDOCTYPE宣言を書かなければHTML 3.2に適合しません [HTML 3.2 Reference Specificationを参照]。

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
... (略) ...
</html>

1.3 SGMLとHTMLの関係

HTMLはSGMLの応用の一つであるといえます。少なくともその構文は SGMLに従っており、文書型はきちんとDTDで定義されています。

しかし、Netscape登場以来HTMLは文書の見栄えの表現に傾いており、 体裁から自由であろうとするSGMLの考え方とはこの点で大きく異なります。 構文だけSGMLに借りて文書の体裁を指定する言語を作るという考え方も あり得ないではないにしても、それは結局TeXやワープロの文書とさほど 変わりないことになり、文書の再利用性を狭めてしまうことになるでしょう。 文書の構造はあくまでSGML的なやり方でマーク付けし、 文書の体裁の指定はHTML文書とは別の形で行うというのが、HTMLの進化の 正しい方向であろうと思います。 しかしHTML 3.2では文書構造の表現については何等改良されず (例えば削除されてしまったHTML3.0の案にあった脚注<fn>はHTML3.2には 存在しない)、 <center>や<font>のごときタグを追加する方向に重きが置かれて います。

HTMLでは章・節といった文書構造は定義されていません。 そのかわりに見出しがh1からh6までの6レベルあるだけなのですが、 レベルの上位・下位はDTDで定義されておらず、h1の次に(h2をとばして) いきなりh3が来ても文書構造として正しいことになってしまいます(これは 良くないスタイルとされているのですが、そういったことは自然言語でなく DTDで表現されるべきことです)。こういった制約の緩さ(あるいはだらしなさ) もHTMLの特徴といえるでしょう。

このようにHTMLがSGML的な考え方からは外れた方向に発展している 状況があるのですが、現在World Wide Web ConsortiumのSGML ワーキンググループでは、インターネット上で使うことを想定したSGMLの サブセットであるXMLの制定が進められています。 XMLはまだドラフトの段階ではありますが、普及すれば現在のHTMLを使うよりも SGMLのより大きな利点をインターネットで享受することができるようになると 思われます。XMLについては An Introduction of the XML が参考になるでしょう。

1.4 要素(element)のマーク付けの仕方

私たちが何気なく見ている文書は構造を持っており、見出し・段落・ 強調句などといった要素から成り立っています。 タグというものがこういった要素を明示するための目印として使われることは 前に述べました。SGML (あるいはHTML)というとタグを使うことがよく知られて いますが、タグは単なる目印に過ぎず、タグによって明示される要素こそが 本質的な存在です。タグそのものは省略や簡略化され得ます。

文書インスタンス中では要素は一般に次のような形でマーク付けされます。

<要素名 属性名=属性値>要素の内容(テキスト)</要素名>

このように要素の内容を、<>の中に要素名を書いた開始タグと </>の中に要素名を書いた終了タグで囲みます。 HTMLでは段落をPという要素として表すことになっていますから、一つの段落全体を <p> ... </p> で囲むことになります。

開始タグではその要素に付随する属性を指定することがあります。 HTMLでは例えば「<img src="image.gif" alt="*">」などと書いて IMG要素のSRC属性とALT属性の値を指定したりしますね。 このように「属性名=属性値」は複数あっても構いません。 属性値は引用符「"」または「'」で括ります(HTMLでは「"」が使われることが ほとんであるようです)。ただし属性値が英数字とハイフン、ピリオドのみから なる場合には引用符を省略できます(これは標準的な文書の場合。SGML宣言に よって異なることもあります)。

文脈上あいまいさが生じない場合には、タグを省略できることが あります。たとえばHTMLで段落を表すには一つの段落全体を<p> ... </p>で囲むと先ほど書きましたが、実際には終了タグ</p>は省略 できます。 また、HTML文書全体を囲む<html>は開始タグも終了タグも 省略できます(書いておいた方が良いことになっているようですが)。 タグを省略できるかできないかはDTDに書かれています(例えば例1 を参照)。

また、内容が空(empty)である要素もあります。HTMLでは<img>や <br>などがそうです。この場合、終了タグは書いてはならず、 開始タグだけで使われます。これもDTDで決められています。

なお、タグに書かれる要素名・属性名は大文字小文字を区別しません。 つまり、<TITLE>と書いても<title>と書いても同じものと みなされます。

ここでごく簡単なHTML文書を例にとってマーク付けの実際を 見てみましょう。下の例で、「-- ... --」はコメントと思って下さい。

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> -- 使用するDTD --
<html>                       -- html要素の始まり --
<head>                       -- head要素の始まり --
<title>HTMLの書き方</title>  -- title要素はhead要素の中に現れる --
</head>                      -- head要素の終わり --
<body>                       -- body要素の始まり --
<h1>HTMLの書き方</h1>        -- h1要素 (レベル1の見出し) --
<p>HTMLは<em>こうやって</em>書きます。 -- p要素(段落)の中には
                                         em要素(強調句)も現れ得る --
<hr>                         -- hr要素はempty elementだから開始タグのみ。
                             hrが現れたことでp要素は暗黙のうちに終わる --
<address>                    -- address要素(署名)の始まり --
権兵衛<br>                   -- br要素(改行)はempty element --
e-mail: somebody@foo.bar.jp
</address>                   -- address要素の終わり --
</body>                      -- body要素の終わり --
</html>                      -- html要素の終わり --

この例での要素の包含関係は次の図のようになります。 タグの付け方と対応していることを確認して下さい。

[文書の構造 (GIF画像, 3KB)]

1.5 実体参照

HTMLで不等号を &lt; と書くようなことを実体参照 と呼びます。これもDTDで定義されます。実体名(amp, lt, gt 等)は大文字小文字を区別します。

「実体」の中でも、文書インスタンス中で&lt;のように参 照されるものは一般実体と呼ばれます。一方、DTDの中に 書かれるパラメータ実体というものもあります。これは 後に挙げる例の中で頻繁に出てきますので、そのときに説明しまし ょう。


第2章 HTMLのDTDを読解する

では実際にHTMLの DTDを読んでみましょう。といっても全部を解説するのは 大変なので、部分的に引用していくつかの読解例を示すことにします。なお、 ここでHTMLのバージョンは2.0とします。HTML3.2のDTD では変更になっているところもあるのですが、DTDを読むためのノウハウは共通です。

2.1 例1: 定義リストの宣言を読む

一つめの例として、定義リスト<dl>の要素宣言の部分をとりあげて みましょう。HTML2.0の DTDから該当部分を引用すると下のようになっています。

<!ELEMENT DL    - -  (DT | DD)+>

「<!ELEMENT DL ... >」というのが、DL要素についての要素宣言である ことを表します。

要素名DLの次の「- -」はタグの省略についての記述です。 一つめの「-」が開始タグ、二つめが終了タグについて、省略できないことを 意味しています。このように「省略不可」を表すのが「-」で、逆に「省略可」の 場合には「O」("Omit"に由来)が書かれます。

次の「(DT | DD)+」は、DL要素の内容がどんなものかを表しています。 この場合、「(DTかDDのどちらか一方)が一回以上繰り返す」ことを意味します。 「|」は「いずれか一つ」を表し、後ろにくっついた「+」は「一回以上の繰り返し」 を表しています。この宣言によるとDLの中のDTとDDの順番は問わないので、 例えば次のような書き方は可能ということになります。

<dl>
<dt>Word A
<dt>Word B
<dd>Definition (description)
</dl>

それでは次に、DL要素の属性宣言を見てみます。HTML2.0のDTDでは、 上の要素宣言に続いて次のように書かれています。

<!ATTLIST DL
        COMPACT (COMPACT) #IMPLIED
        %SDAFORM; "List"
        %SDAPREF; "Definition List:"
        >

「<!ATTLIST DL ... >」が、DL要素の属性宣言であることを 表します(ATTLISTとはattribute definition listでしょうか)。属性宣言では、 属性名、宣言値(とり得る属性値)、省略時の属性値をどうするかのキーワードが 順に並んでいます。

上の例の2行目「COMPACT (COMPACT) #IMPLIED」は、「COMPACTという 属性は、属性値としてCOMPACTをとることができる。指定を省略した時の属性値は 暗黙の内にアプリケーション側で決められる」ということを意味します。 ここで属性名と属性値が同じなのはたまたまです。

文書インスタンス(要するにHTML文書)でDLの属性を指定する時には、 普通の書き方では「<dl compact=compact>」と書くことになります。 しかしこの場合、属性名compactを省略しても属性値compactがcompact属性の 値であることは明らかなので、属性名を省略することができます。つまり、 「<dl compact>」と書くことが可能なわけです。

なお、上の例の3,4行目は無視しておきます。わからなくても 別段困りはしないでしょう。

ここまででDL要素を調べました。今度はDLの中に含まれるDT要素(定義語)と DD要素(定義文)を見てみましょう。 この二つの要素宣言は次のように書かれています(属性宣言は省略)。

<!ELEMENT DT    - O (%text)*>

<!ELEMENT DD    - O %flow>

「DT要素は、開始タグは省略不可、終了タグは省略してよい。その内容は %text;の0回以上の繰り返し」と書かれています。(%text)*の「*」は 「0回以上の繰り返し」を表します。終了タグを省略してよいというので 気付いたかもしれませんが、定義リストで普通「<dt>...<dd>...」 と書いているのは、実は<dd>の前にある筈の終了タグ</dt>を 省略しているわけです。

問題は、「%text」とは何か、でしょう。これは、DTDのこれ以前の部分で textという名前のパラメータ実体が宣言されており、それを参照するときに 「%text」と書くのです。パラメータ実体は、いうなればC言語のマクロの ようなものです。

ではそのパラメータ実体を宣言している部分を見てみましょう。 HTML2.0では下のように宣言されています。

<!ENTITY % text "#PCDATA | A | IMG | BR | %phrase | %font">

実体宣言は「<!ENTITY ... >」と書かれます。ここではパラメータ 実体宣言をとりあげていますが、&lt;のような「一般実体」の宣言も 同じような形で書かれます。

上の記述により、%text;と書かれた部分は「#PCDATA | A | IMG | BR | %phrase | %font」と読みかえればいいことが分かります。#PCDATAは、Parsed Character Dataの意味で、解析の対象となるテキストデータを表します。要するに普通の 文字だと思っていいでしょう。なお、%text;の「;」は単なる区切りで、 書かなくてもいい場面もあるようですが、筆者はよく知りません。まあ 自分でDTDを書くのでなければあまり気にしなくていいでしょう。

%text;の実体宣言の中にもまた、%phrase;と%font;という二つのパラメータ 実体参照が出てきています。さらにDTDを遡って調べると、この二つの実体は 次のように宣言されていました。%phrase;と%font;はそれぞれ下の引用符の 中の文字列で置き換えて読めば良いわけです。

<!ENTITY % font " TT | B | I ">

<!ENTITY % phrase "EM | STRONG | CODE | SAMP | KBD | VAR | CITE ">

DT要素に戻りましょう。上のことをまとめると、DT要素の中に現れてよい要素は、 A, IMG, BR, EM, STRONG, CODE, SAMP, KBD, VAR, CITE, TT, B, I である ことが分かりました。タグで囲まれない普通の文字データ(#PCDATA)を書いても いいことも分かりました。

では同様にしてもう一つ、DD要素の中に現れ得る要素を調べてみましょう。 DDの内容モデルは「%flow」と書かれていたのでした。パラメータ実体flowの 宣言を探しましょう。

<!ENTITY % flow "(%text|%block)*">

%text;は先ほど出てきました。%block;は下のように宣言されています。

<!ENTITY % block "P | %list | DL
        | %preformatted
        | %block.forms">

%list;と%preformatted;と%block.forms;の宣言はそれぞれ以下の通り。

<!ENTITY % list " UL | OL | DIR | MENU " >

<!ENTITY % preformatted "PRE">

<!ENTITY % block.forms "BLOCKQUOTE | FORM | ISINDEX">

延々と実体宣言を追いかけてきましたが、以上のことを総合すると、 DD要素の内容モデルは結局 (#PCDATA | A | IMG | BR | EM | STRONG | CODE | SAMP | KBD | VAR | CITE | TT | B | I | P | UL | OL | DIR | MENU | DL | PRE | BLOCKQUOTE | FORM | ISINDEX)* だということが分かります。やれやれ、一仕事でした。

2.2 例2: IMG要素の宣言を読む

また別の例として、インラインイメージを表すIMG要素の宣言を見てみましょう。 なお、前の例と同様に属性宣言の最後の%SDAPREF;云々は無視して下さい。

<!ELEMENT IMG    - O EMPTY>
<!ATTLIST IMG
        SRC CDATA  #REQUIRED
        ALT CDATA #IMPLIED
        ALIGN (top|middle|bottom) #IMPLIED
        ISMAP (ISMAP) #IMPLIED
        %SDAPREF; "<Fig><?SDATrans Img: #AttList>#AttVal(Alt)</Fig>"
        >

IMG要素の内容モデルはEMPTYと書かれています。この場合に終了タグは 書いてはならず、開始タグだけが使われます。

属性宣言の方を見てみましょう。SRC属性の宣言値として、キーワード CDATAが書かれています。これは文字データを意味し、空文字列も許します。 IMGのSRC属性といえば画像ファイルを指すURLを意味するのですから、 このように任意の文字列をとることができるように指定されているわけです。

SRC属性の省略時のキーワードとして「#REQUIRED」と書かれています。 これは、この属性は必須であり、属性値の指定を省略してはならないことを 意味します。

ALT, ALIGN, ISMAPの各属性について、宣言されている内容を読み下して みましょう。

ALT
属性値は任意の文字列。省略時の値はアプリケーションが決める。

- ALT属性は#IMPLIEDとして宣言されてはいますが、 実際には必ずALT属性の値を指定すべきです。理由は「好ましいHTML文書を書くための方法と考え方」(矢野)の 「<IMG>にはALTテキストを適切に付ける」の 節をご覧ください。

ALIGN
属性値は TOP, MIDDLE, BOTTOM のいずれか。省略時の値はアプリケーションが 決める。
ISMAP
属性値はISMAP。省略時の値はアプリケーションが決める。

2.3 例3: アンカーの宣言を読む

HTMLの大きな特徴がアンカー、つまり他の文書にリンクを張ったり 文書の一部をリンクの飛び先として指定したりする部分です。これには <A>タグ(AnchorのAですね)が使われます。この<A>の要素宣言と 属性宣言を調べてみましょう。

<![ %HTML.Recommended [
        <!ENTITY % A.content   "(%text)*"
        -- <H1><a name="xxx">Heading</a></H1>
                is preferred to
           <a name="xxx"><H1>Heading</H1></a>
        -->
]]>

<!ENTITY % A.content   "(%heading|%text)*">

<!ELEMENT A     - - %A.content -(A)>
<!ATTLIST A
        HREF CDATA #IMPLIED
        NAME CDATA #IMPLIED
        %linkExtraAttributes;
        %SDAPREF; "<Anchor: #AttList>"
        >

ここでパラメータ実体%heading;は、見出しh1, h2, ..., h6を 表しています。%text;は先ほどの例と同じです。また、HREFとNAME以外の 属性はほとんど使われないのでここでは無視します。

この例では%A.content;のパラメータ実体宣言が2箇所見られます。 そのうち一つは「<![ %HTML.Recommended [ ... ]]>」で囲まれています。 想像がつくかと思いますが、DTDの作者はこちらの方を推奨しているわけです (これはSGMLの機能の一つを使って書かれているのですが、詳しく立ち入ることは しません)。

"Recommended"の方を見ると、コメントとして(「-- ... --」で囲まれた 範囲はコメントです)、<A>タグで<H1> ... </H1>を囲む 書き方はよろしくないと書かれています。実際、"Recommended"の方の要素 宣言では%A.content;(A要素の内容)に%heading;(見出し)が入らないことに なっていますね。見出しにnameを振る場合は、見出しの中の文字列を <A NAME="..."> ... </A>で囲めばいいわけです。

また、ときどき「<a name="..."> ... </a>」が閉じていない (</a>がない)文書を見かけますが、この書き方は間違いであることが 要素宣言から分かるでしょう。 終了タグを省略できないように宣言されているからです。

さて、要素宣言のところで、内容モデルの記述に「-(A)」というのが くっついています。これは「ただしA要素は除く」と読めばいいでしょう。 実体参照を追いかけていくと%A.content;にA要素が入っていることが分かるの ですが、この記述を付け足すことでアンカータグがネストすることを禁じて いるのです。この書き方は次の例でまた出てきます。

なお、アンカーをどのように付けるべきかについては「好ましいHTML文書を 書くための方法と考え方」(矢野)の「アンカーの指定の仕方」の節にまとめて おきましたのでご覧ください。

2.4 例4: HEADおよびTITLE要素の宣言を読む

もう一つの例として、HTML文書のはじめの部分に現れるHEAD要素について その宣言を見てみましょう。

<!ENTITY % head.content "TITLE & ISINDEX? & BASE? %head.extra">

<!ELEMENT HEAD O O  (%head.content) +(META|LINK)>

HEAD要素は開始タグも終了タグも省略可能。内容モデルの%head.content; ですが、実体宣言を見ると、いくつかの名前が「&」で並んでいます。 「|」で並べると「いずれか一つ」を意味したのに対し、この場合は「順不同に 一つずつ現れる」ことを意味します。ISINDEXとBASEの後に付いている「?」は 「0回または1回出現」を意味するので、上の%head.content;は「TITLE, ISINDEX, BASE, %head.extra;が順不同に一つずつ現れるが、ISINDEXとBASEは あってもなくてもよい」ことになります(だから、TITLEは必ずなくてはならないと いうことでもあります)。なお、%head.extra;は古いバージョンのHTMLとの 互換性のためにあるもので、ここでは空だと思って構いません。

HEAD要素の内容モデルには、さらに「+(META|LINK)」というのがくっついて います。これは、示された内容モデル(%head.content)の下位の構造において (META|LINK)がどこに出てきてもよいことを表しています。

では次に、HEADの中に現れるTITLE要素の宣言を読んでみます。

<!ELEMENT TITLE - -  (#PCDATA)*  -(META|LINK)>

今度は、内容モデルに「-(META|LINK)」というのがくっついています。 これは先ほどの「+」の逆で、その下位構造において(META|LINK)が現れることを 禁止するものです(この書き方は<A>の要素宣言のところでも出て きましたね)。TITLEの内容モデルは#PCDATA、要するに普通の文字列で あるわけです。しかしHEADの要素宣言に「+(META|LINK)」があったので、 HEADの下位にあたるTITLEの中でそれらが出てき得ることになってしまいます。 それを禁止するために「-(META|LINK)」を書いているわけです。

おわりに

この説明だけでHTMLのDTDが全て読めるというわけでもないのですが、 実際的な例を示したとは思っています。より詳しくは下記の参考文献を お読み戴きたいのですが、厳密さを要求しないのであれば、上の説明の 範囲外であっても文中に挙げた例からの類推でなんとか読めるのではないかと 思います。

わかりづらいところや間違った記述もあるかもしれませんが、その際は メールにてご批判を 戴ければ幸いです。


参考文献

SGMLについて日本語で書かれた本は数えるほどしかありません。 ここでは、書店で入手しやすく、SGMLの書き方について一通り解説している本を 筆者の知る範囲で挙げておきます。

WWWで利用できるリソース:

Special Thanks to TAKAHASHI "Maki" Masayoshi


広告

1996年10月 初版公開, 1997年5月12日 最終更新

矢野啓介 (Email: yano@moon.email.ne.jp)