Document Object Model
Document Object Model (DOM) は、HTMLやXML文書をプログラムから操作するための標準的なインターフェースです。重要な点として、DOMはJavaScriptに限定されたものではなく、言語に依存しない仕様として設計されています。
基本概念
編集DOMツリー
編集DOМは文書を「ノード」の木構造として表現します。主なノードの種類:
- Document - 文書全体を表すルートノード
- Element - HTML要素
- Attribute - 要素の属性
- Text - テキストコンテンツ
- Comment - コメント
- コード例(JavaScript)
// 要素の取得 const element = document.querySelector('#example'); // 子要素へのアクセス const children = element.childNodes; // 親要素へのアクセス const parent = element.parentNode;
要素の操作
編集要素の検索
編集- querySelector()
- querySelectorAll()
- getElementById()
- getElementsByClassName()
- getElementsByTagName()
- コード例
// ID指定 const element = document.querySelector('#myId'); // クラス指定 const elements = document.querySelectorAll('.myClass'); // CSSセレクタ const selected = document.querySelector('.myClass > p');
要素の作成と追加
編集- コード例(JavaScript)
// 新しい要素の作成 const newDiv = document.createElement('div'); // テキストの設定 newDiv.textContent = 'Hello, DOM!'; // 属性の設定 newDiv.setAttribute('class', 'myClass'); // DOMツリーへの追加 document.body.appendChild(newDiv);
- コード例(Java)
import org.w3c.dom.*; DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.newDocument(); // 要素の作成 Element div = doc.createElement("div"); // テキストの設定 div.setTextContent("Hello, DOM!"); // 属性の設定 div.setAttribute("class", "myClass");
イベント処理
編集- コード例(JavaScript)
// イベントリスナーの追加 element.addEventListener('click', function(event) { console.log('要素がクリックされました'); }); // イベントの削除 const handler = function(event) { // 処理 }; element.removeEventListener('click', handler);
属性の操作
編集- getAttribute()
- setAttribute()
- removeAttribute()
- hasAttribute()
- コード例
// 属性の取得 const value = element.getAttribute('data-value'); // 属性の設定 element.setAttribute('class', 'newClass'); // 属性の削除 element.removeAttribute('style'); // 属性の存在確認 if (element.hasAttribute('id')) { // 処理 }
DOM操作のベストプラクティス
編集パフォーマンスの最適化
編集- DOM操作は最小限に抑える
- DocumentFragmentの使用
- 要素の再利用
- バッチ処理の活用
- コード例
// DocumentFragmentの使用例 const fragment = document.createDocumentFragment(); for (let i = 0; i < 1000; i++) { const div = document.createElement('div'); div.textContent = `Item ${i}`; fragment.appendChild(div); } document.body.appendChild(fragment);
クロスブラウザ対応
編集- 標準的なDOM APIの使用
- ポリフィルの活用
- ブラウザ固有の機能の確認
高度なDOM操作
編集DOM Range
編集テキストや要素の範囲を操作するためのAPI
- コード例
const range = document.createRange(); const selection = window.getSelection(); const paragraph = document.querySelector('p'); range.selectNodeContents(paragraph); selection.removeAllRanges(); selection.addRange(range);
DOM Mutation Observer
編集DOM変更の監視
- コード例
const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { console.log('DOM変更:', mutation.type); }); }); observer.observe(targetNode, { childList: true, attributes: true, subtree: true });
セキュリティの考慮事項
編集クロスサイトスクリプティング(XSS)対策
編集- textContent の使用(innerHTML の代わりに)
- 入力値のサニタイズ
- Content Security Policy (CSP) の実装
- コード例
// 安全なテキスト挿入 element.textContent = userInput; // 危険な例(使用を避ける) element.innerHTML = userInput;
DOM標準の沿革
編集誕生の背景(1995-1997)
編集DOMの標準化以前、ブラウザ各社は独自のAPIを実装していました:
- Netscape NavigatorのDocument API
- Internet ExplorerのDocument All コレクション
これらの互換性の無さが、Web開発者に大きな困難をもたらしていました。
Level 0 DOM
編集- 正式な仕様ではなく、事実上の標準
- Netscape Navigator 3.0とInternet Explorer 3.0で実装された基本的なDOM機能
- document.forms, document.images, document.links などの基本的なコレクション
- 限定的な要素操作機能
Level 1 DOM(1998)
編集- W3Cによる最初の正式なDOM仕様
- HTMLとXMLの基本的な文書構造とマニピュレーション機能を定義
- 主な特徴:
- 文書を階層的なノードツリーとして定義
- 基本的なノード操作メソッド(appendChild, removeChild など)
- 要素とその属性へのアクセス方法
- コード例(Level 1の基本機能)
// Level 1 DOMの基本的な操作 const element = document.createElement('div'); const text = document.createTextNode('Hello DOM Level 1'); element.appendChild(text); document.body.appendChild(element);
Level 2 DOM(2000)
編集- より高度なイベント処理モデルを導入
- 名前空間のサポート
- スタイルシートとCSSのプログラム的操作
- DOM Viewsの導入
- トラバーサル(文書走査)メソッドの拡張
- コード例(Level 2のイベント処理)
// Level 2のイベントリスナー element.addEventListener('click', function(e) { // イベントの伝播を制御 e.stopPropagation(); // デフォルト動作を防止 e.preventDefault(); }, false);
Level 3 DOM(2004)
編集- XPath統合
- キーボードイベントの標準化
- 文書の検証とロード
- 文書保存の機能
- コンテンツモデルとドキュメント検証
DOM Living Standard(2015-現在)
編集- WHATWG(Web Hypertext Application Technology Working Group)による管理
- 継続的に更新される「Living Standard」方式を採用
- モダンなWeb APIとの統合
- 新しい機能の継続的な追加:
- Shadow DOM
- Custom Elements
- Template elements
- MutationObserver
- コード例(モダンなDOM機能)
// Shadow DOMの使用例 class CustomElement extends HTMLElement { constructor() { super(); const shadow = this.attachShadow({mode: 'open'}); const div = document.createElement('div'); div.textContent = 'Shadow DOM Content'; shadow.appendChild(div); } } customElements.define('custom-element', CustomElement);
重要な仕様の分割
編集現代のDOM標準は、より小さく管理しやすい仕様に分割されています:
- DOM Core - 基本的なDOM操作
- DOM Events - イベント処理
- DOM Parsing - 文書の解析とシリアライズ
- DOM Range - テキスト範囲の操作
- DOM Traversal - 文書走査
- DOM XPath - XPathサポート
ブラウザ実装の変遷
編集- 1990年代後半: 各ブラウザの独自実装
- 2000年代前半: 標準化への緩やかな対応
- 2000年代後半: より厳密な標準準拠
- 2010年代: モダンブラウザによる高度な機能の実装
- 現在: 主要ブラウザ間での高い互換性
DOMの将来
編集- Web Componentsとの更なる統合
- パフォーマンス最適化
- セキュリティ強化
- 新しいWeb APIとの連携
- リアクティブプログラミングモデルとの統合
WebIDLとDOM実装
編集WebIDLの役割
編集WebIDL(Web Interface Definition Language)は、WebプラットフォームのAPIを形式的に定義するための言語です。主な目的:
- インターフェース定義の標準化
- 言語バインディングの自動生成
- 型安全性の確保
- API仕様の明確化
ブラウザでの実装プロセス
編集主要ブラウザエンジンは、WebIDL定義からネイティブコードを生成します:
- Chromium (Blink)
- bindings/scripts/が変換処理を担当
- IDLファイルから C++ コードを生成
- V8エンジンとのバインディングも自動生成
- 例
- Elementインターフェースの定義
[Exposed=Window] interface Element : Node { readonly attribute DOMString? namespaceURI; readonly attribute DOMString? prefix; readonly attribute DOMString localName; readonly attribute DOMString tagName; [CEReactions] attribute DOMString id; [CEReactions] attribute DOMString className; [SameObject, PutForwards=value] readonly attribute DOMTokenList classList; [CEReactions, Unscopable] attribute DOMString slot; boolean hasAttributes(); [SameObject] readonly attribute NamedNodeMap attributes; sequence<DOMString> getAttributeNames(); DOMString? getAttribute(DOMString qualifiedName); DOMString? getAttributeNS(DOMString? namespace, DOMString localName); [CEReactions] void setAttribute(DOMString qualifiedName, DOMString value); [CEReactions] void setAttributeNS(DOMString? namespace, DOMString qualifiedName, DOMString value); [CEReactions] void removeAttribute(DOMString qualifiedName); [CEReactions] void removeAttributeNS(DOMString? namespace, DOMString localName); boolean hasAttribute(DOMString qualifiedName); boolean hasAttributeNS(DOMString? namespace, DOMString localName); };
- Firefox (Gecko)
- WebIDL ParserがIDLファイルを解析
- バインディングジェネレータがC++コードを生成
- SpiderMonkeyエンジンとの連携コードも生成
- WebKit
- IDLファイルからObjective-C/C++コードを生成
- JavaScriptCoreとのバインディング生成
生成されるコードの種類
編集WebIDLから生成される主なコード:
- インターフェース実装
- C++/Objective-Cでの実際のクラス定義
- メソッドとプロパティの実装
- バインディングレイヤー
- JSエンジンとネイティブコード間の橋渡し
- 型変換処理
- 例外処理
- テストコード
- インターフェース準拠テスト
- Web Platform Testsとの統合
コード生成の例
編集- WebIDL定義
interface HTMLImageElement : HTMLElement { [HTMLConstructor] constructor(); [CEReactions] attribute DOMString alt; [CEReactions] attribute DOMString src; [CEReactions] attribute DOMString srcset; [CEReactions] attribute DOMString sizes; [CEReactions] attribute DOMString crossOrigin; [CEReactions] attribute DOMString useMap; [CEReactions] attribute boolean isMap; [CEReactions] attribute unsigned long width; [CEReactions] attribute unsigned long height; readonly attribute unsigned long naturalWidth; readonly attribute unsigned long naturalHeight; readonly attribute boolean complete; readonly attribute DOMString currentSrc; [CEReactions] attribute DOMString decoding; [CEReactions] attribute DOMString loading; Promise<void> decode(); };
- 生成されるC++コード(概念的な例)
class HTMLImageElement : public HTMLElement { public: // コンストラクタ static HTMLImageElement* Create(Document&); // 属性アクセサ String alt() const; void setAlt(const String&); String src() const; void setSrc(const String&); unsigned width() const; void setWidth(unsigned); // 読み取り専用プロパティ unsigned naturalWidth() const; unsigned naturalHeight() const; // メソッド Promise<void> decode(); private: // 実装詳細 String m_alt; String m_src; unsigned m_width; // ... };
パフォーマンスの考慮
編集WebIDLからの自動生成には以下の最適化が含まれます:
- キャッシング戦略
- プロパティアクセスの最適化
- メソッド呼び出しのキャッシング
- メモリ最適化
- 適切なメモリレイアウト
- 仮想メソッドテーブルの最適化
- 型変換の最適化
- 高速な型チェック
- 効率的な値の変換
拡張と制約
編集- 拡張属性
- [CEReactions] - Custom Elements
- [Exposed] - グローバルスコープ
- [SameObject] - オブジェクト同一性
- [PutForwards] - 転送属性
- 制約
- セキュリティチェック
- 型チェック
- 値の範囲チェック
デバッグとトレース
編集- バインディングデバッグ情報の生成
- パフォーマンスプロファイリングのサポート
- エラー報告メカニズム
まとめ
編集DOMは、プログラミング言語に依存しない、文書操作のための強力なインターフェースです。JavaScriptだけでなく、多くのプログラミング言語でDOMを使用することができ、これによって文書の構造化された操作が可能になります。