DOMはHTMLドキュメントなどをツリー状のデータ構造として取り扱い、これを参照/操作するためのデータ構造やインタフェースを定義したもの。
Document Object Model(DOM)は、HTMLドキュメントおよびXMLドキュメントをツリー状のデータ構造として扱い、それをプログラムから参照したり操作したりするためのデータ構造やインタフェース(API)を定義したもの。W3CおよびWHATWGにより仕様が策定されている。
DOMはこれまでにW3CによりLevel 1〜4が勧告されている。その一方、現在ではWHATWGがDOM Living Standard(変更が継続的に行われる標準)として策定をしている(W3Cが2015年11月に勧告したDOM Level 4はWHATWGのDOM Living Standardをベースとしたもの)。
DOMが定義しているのは、「ドキュメントの論理的な構造」と「ドキュメントにアクセスしたり、それを操作したりするための手法」である。DOMではHTMLドキュメントなどを「ツリー」状の構造として扱う。よくある例だが、以下のようなHTMLドキュメントがあったとしよう。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Document</title>
</head>
<body>
<h1>Title</h1>
<ul>
<li>item1</li>
<li>item2</li>
</ul>
</body>
</html>
DOMでは、これを以下のような「オブジェクトがツリー構造に形成されたもの」として扱う。これを「ドキュメントツリー」「DOMツリー」などと呼ぶ。また、「ドキュメントツリーの操作」(特定のノードを参照したり、それを変更したりすること)を短く「DOM操作」と呼ぶこともよくある。
ツリーを構成する個々の要素のことを「ノード」と呼ぶ。ノードは「メソッドやプロパティ」といった属性を持った「オブジェクト指向言語におけるオブジェクト」と同様なものである。DOMが定めるのは、これらのオブジェクトが「どのような属性を持つか」の抽象的な定義(インタフェース)であり、その実装はドキュメントをパースして、ツリー状のデータ構造を作成するプログラムに委ねられている。そうしたプログラムの代表的なものがWebブラウザといえる。
HTMLなどのドキュメントをパースした結果として作成されるツリーのルートとなるのは、皆さんおなじみの「document」オブジェクトだ。このオブジェクトが実装しているDocumentインタフェースはDOM Living Standardの定義を借りると、次のようになっている(実際には、Documentインタフェースを拡張した「HTMLDocument」インタフェース)。
interface Document : Node {
// …… 省略 …・
HTMLCollection getElementsByTagName(DOMString qualifiedName);
// …… 省略 …・
[CEReactions, NewObject] Element createElement(DOMString localName,
optional (DOMString or ElementCreationOptions) options);
// …… 省略 …・
};
「var elms = document.getElementsByTagName(……)」のようにして使ったことがあるであろうメソッドが定義されていることが分かる(最も有名であろうgetElementByIdメソッドはまた別のインタフェースで定義されているが、Documentインタフェースではそのインタフェースを「ミックスイン」することで、このメソッドが使えるようになっている)。
このように、ツリーを構成するノードはオブジェクトであり、それぞれがその種類(型)に応じたプロパティや操作を公開している。ソースとなる(例えば)HTMLドキュメントをWebブラウザなどのプログラムが読み込んで、そこからドキュメントツリーを構築することで、それぞれのノード(オブジェクト)が公開している各種のプロパティやメソッドをプログラミング言語(多くの場合ECMAScriptのことだ)が扱えるようになる。
ドキュメントツリーを形成するノードには次のような種類がある。冒頭に示した図ではこれらの種類ごとに色を分けてある。
この他にも、ドキュメントの種類を表すDocumentTypeインタフェース、ドキュメントツリーの一部分を表すDocumentFragmentインタフェースなど、ノードを形成するオブジェクトにはいろいろなものがある。
DOMが定めるのは、そうしたオブジェクトがどういう意味合いで使われ、どんなプロパティやメソッドを持つかや、それらのオブジェクトがどのような関係を持っているかといった事柄だ。
そして、DOMが定めるさまざまなインタフェースを利用することで、プログラミング言語からはDOMの内容を参照したり、動的にその内容を変更したりできるようになる。例えば、以下のようなコードを考えてみよう。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title id="title">Document</title>
</head>
<body>
<script>
var pnode = document.createElement("p");
var textnode = document.createTextNode("Hello world");
pnode.appendChild(textnode);
document.body.appendChild(pnode);
</script>
</body>
</html>
ここでは<script>要素内で<body>要素内に<p>要素を追加している。コードを見ると分かるが、document.createElementメソッドで<p>要素を作成し(これは上で見たElement型のノード)、さらにdocument.createTextNodeメソッドでそこに表示するテキストを含んだノードを作成してから(こちらは上で見たText型のノード)、<p>要素の子ノードとしてテキストノードを追加している。ノードを作成しただけでは、それはブラウザに表示されない。それをドキュメントツリーへと挿入する(ここでは<body>要素の子ノードとして追加する)ことで、「Hello world」と表示されるようになる。
Webコンテンツを動的に生成するには、このように生のDOMをそのまま操作してもよいが、実際にそうしようとすると、その処理は煩雑なものになる(上で見たように、要素とそこに表示するテキストを追加するだけでも面倒だ)。そこで登場したのが、jQueryをはじめとした、DOM操作を簡単にしてくれるライブラリだ。さらに最近では、ReactやVue.jsなど、「Virtual DOM」と呼ばれる機構を採用したフレームワークも広く使われるようになってきている。DOMの操作は負荷が比較的高い操作であることから、DOMを操作するたびにそれをWebブラウザへと反映するのではなく、通常は仮想的なDOMを操作しておいて、必要なタイミングでのみWebブラウザに反映するようにすることで、より応答性の高いWebアプリを作成しようというのが、仮想DOMフレームワークを普及させる原動力となっている。
なお、本稿冒頭でも述べたが、DOMそのものはHTMLドキュメントやXMLドキュメントをドキュメントツリーの形で扱うためのものであり、HTMLドキュメントに対応するDOMの仕様はコアとなる部分とは別に定義されている。例えば、古いDOM Level 1では「Chapter 1: Document Object Model (Core) Level 1」でコア部分が、「Chapter 2: Document Object Model (HTML) Level 1」でHTMLに関連する部分が定められている。WHATWGでは「DOM Living Standard」と「HTML Living Standard」が相互に参照し合う形でHTMLのDOMに関する仕様が定まっているといえる。Living Standardが提供している一次情報に当たって、詳しく調べようというときには、両者を参照することになるだろう。
DOMはHTMLドキュメント/XMLドキュメントを、ツリー状のデータ構造として取り扱い、これを参照したり、操作したりするためのデータ構造やインタフェースを定義している。プラットフォーム(例:Webブラウザ)やプログラミング言語とは独立した仕様とすることで、多くのプログラム/プログラミング言語がHTMLドキュメントやXMLドキュメントを透過的に扱うことができるようになっている。
Copyright© Digital Advantage Corp. All Rights Reserved.