Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【PHP8.x】DOMDocumentFragment::DOCUMENT_POSITION_CONTAINED_BY定数の使い方

DOCUMENT_POSITION_CONTAINED_BY定数の使い方について、初心者にもわかりやすく解説します。

作成日: 更新日:

基本的な使い方

DOCUMENT_POSITION_CONTAINED_BY定数は、PHPのDOM拡張機能において、二つの異なるDOMノード間の相対的な位置関係を判断する際に使用されるビットマスク定数の一つです。この定数は、主にDOMNode クラスが提供するcompareDocumentPosition() メソッドの戻り値として利用されます。

具体的にこの定数が表すのは、比較対象となるノードが、基準となるノードの内部に「含まれている」という関係性です。たとえば、HTMLドキュメント内で <p> タグが <div> タグの子要素として存在する場合、<div> タグを基準ノードとして <p> タグと比較すると、DOCUMENT_POSITION_CONTAINED_BY のビットが戻り値に含まれる可能性があります。これは、基準ノードが比較対象ノードの親、または祖先ノードであることを示唆します。

compareDocumentPosition() メソッドの戻り値は、複数の位置関係を示す定数のビットマスク(ビット演算による組み合わせ)として返されるため、この定数単独で位置関係のすべてを表すわけではありません。他の定数、例えば DOCUMENT_POSITION_CONTAINS などと組み合わせて評価することで、より詳細なノード間の関係性を把握できます。システムエンジニアを目指す方々にとって、DOMツリー内での要素の配置をプログラム的に正確に判別し、複雑なDOM操作を行う上で不可欠な情報を提供する定数です。

構文(syntax)

1<?php
2echo DOMDocumentFragment::DOCUMENT_POSITION_CONTAINED_BY;

引数(parameters)

引数なし

引数はありません

戻り値(return)

戻り値なし

戻り値はありません

サンプルコード

PHP DOMノード位置関係比較:PRECEDINGとCONTAINED_BY

1<?php
2
3/**
4 * DOMNode::compareDocumentPosition メソッドを使ってノード間の位置関係を比較し、
5 * その結果をシステムエンジニアを目指す初心者にも分かりやすく出力するサンプルコードです。
6 *
7 * DOM_DOCUMENT_POSITION_CONTAINED_BY 定数と DOM_DOCUMENT_POSITION_PRECEDING 定数に
8 * 焦点を当てていますが、他の主要な位置関係も合わせて表示します。
9 */
10
11// 1. 新しいDOMドキュメントを作成します。
12// XML宣言 (バージョン1.0、UTF-8エンコーディング) を含めます。
13$dom = new DOMDocument('1.0', 'UTF-8');
14// 出力時にXMLを整形し、読みやすくします。
15$dom->formatOutput = true;
16
17// 2. DOMツリーを構築するための要素を作成し、追加します。
18// ルート要素 'root' を作成し、ドキュメントに追加します。
19$root = $dom->createElement('root');
20$dom->appendChild($root);
21
22// 親となる 'div' 要素を作成し、'root' の子として追加します。
23$parentDiv = $dom->createElement('div');
24$parentDiv->setAttribute('id', 'parentDiv');
25$root->appendChild($parentDiv);
26
27// 最初の段落 'p' 要素を作成し、'parentDiv' の子として追加します。
28$childP1 = $dom->createElement('p', 'これは最初の段落です。');
29$childP1->setAttribute('id', 'childP1');
30$parentDiv->appendChild($childP1);
31
32// 2番目の段落 'p' 要素を作成し、'parentDiv' の子として追加します。
33$childP2 = $dom->createElement('p', 'これは2番目の段落です。');
34$childP2->setAttribute('id', 'childP2');
35$parentDiv->appendChild($childP2);
36
37// 3. DOMDocumentFragment を作成し、その中にノードを追加します。
38// DOMDocumentFragment は、ドキュメントツリーの一部として扱われることなく、
39// 複数のノードを一時的に保持するための軽量なコンテナです。
40// DOMNode を継承しているため、compareDocumentPosition メソッドを使用できます。
41$fragment = $dom->createDocumentFragment();
42$fragmentP = $dom->createElement('p', 'これはフラグメント内の段落です。');
43$fragmentP->setAttribute('id', 'fragmentP');
44$fragment->appendChild($fragmentP);
45
46echo "--- DOMノードの位置関係の比較 ---\n\n";
47
48/**
49 * 2つのDOMノード間の位置関係を比較し、結果を分かりやすく出力する関数。
50 *
51 * @param DOMNode $node1 最初のノード(基準となるノード)
52 * @param DOMNode $node2 比較対象のノード
53 * @param string $name1 最初のノードの表示名
54 * @param string $name2 比較対象のノードの表示名
55 */
56function compareAndDescribePosition(DOMNode $node1, DOMNode $node2, string $name1, string $name2): void
57{
58    // compareDocumentPosition メソッドは、ノード間の位置関係を示すビットマスクを返します。
59    // 例: node1がnode2に先行する場合、DOM_DOCUMENT_POSITION_PRECEDING が含まれます。
60    $position = $node1->compareDocumentPosition($node2);
61
62    echo "ノード '{$name1}' と '{$name2}' を比較:\n";
63
64    // ビット演算子 '&' を使用して、返されたビットマスクに特定の定数が含まれているかを確認します。
65    if ($position & DOM_DOCUMENT_POSITION_SAME_NODE) {
66        echo "  - 両方のノードは同じノードです。\n";
67    }
68    // DOM_DOCUMENT_POSITION_CONTAINED_BY: $node1 が $node2 の内部に含まれている場合。
69    // 例: $childP1 は $parentDiv に含まれています。
70    if ($position & DOM_DOCUMENT_POSITION_CONTAINED_BY) {
71        echo "  - '{$name1}' は '{$name2}' に含まれています ('{$name1}'は'{$name2}'の内側)。\n";
72    }
73    // DOM_DOCUMENT_POSITION_CONTAINS: $node1 が $node2 を含んでいる場合。
74    // 例: $parentDiv は $childP1 を含んでいます。
75    if ($position & DOM_DOCUMENT_POSITION_CONTAINS) {
76        echo "  - '{$name1}' は '{$name2}' を含んでいます ('{$name2}'は'{$name1}'の内側)。\n";
77    }
78    // DOM_DOCUMENT_POSITION_PRECEDING: $node1 がドキュメント順で $node2 よりも前に位置する場合。
79    // 例: $childP1 は $childP2 に先行します。
80    if ($position & DOM_DOCUMENT_POSITION_PRECEDING) {
81        echo "  - '{$name1}' は '{$name2}' に先行しています (ドキュメント順で'{$name1}'が'{$name2}'より前)。\n";
82    }
83    // DOM_DOCUMENT_POSITION_FOLLOWING: $node1 がドキュメント順で $node2 よりも後に位置する場合。
84    // 例: $childP2 は $childP1 に後続します。
85    if ($position & DOM_DOCUMENT_POSITION_FOLLOWING) {
86        echo "  - '{$name1}' は '{$name2}' に後続しています (ドキュメント順で'{$name1}'が'{$name2}'より後)。\n";
87    }
88    // DOM_DOCUMENT_POSITION_DISCONNECTED: 両ノードが同じドキュメントツリー内にない場合。
89    // 例: ドキュメントフラグメント内のノードと、メインドキュメントのノード。
90    if ($position & DOM_DOCUMENT_POSITION_DISCONNECTED) {
91        echo "  - ノードは切断されています(同じドキュメントやフラグメントに属していないか、まだ接続されていません)。\n";
92    }
93    echo "\n";
94}
95
96// === 比較の例 ===
97
98// 例1: DOM_DOCUMENT_POSITION_CONTAINED_BY の例
99// $childP1 は $parentDiv の子なので、$childP1 は $parentDiv に含まれています。
100compareAndDescribePosition($childP1, $parentDiv, '$childP1', '$parentDiv');
101
102// 例2: DOM_DOCUMENT_POSITION_PRECEDING の例
103// $childP1 は $childP2 よりもドキュメントツリーで前に位置します。
104compareAndDescribePosition($childP1, $childP2, '$childP1', '$childP2');
105
106// 例3: DOM_DOCUMENT_POSITION_FOLLOWING の例 (PRECEDING の逆)
107// $childP2 は $childP1 よりもドキュメントツリーで後に位置します。
108compareAndDescribePosition($childP2, $childP1, '$childP2', '$childP1');
109
110// 例4: DOM_DOCUMENT_POSITION_CONTAINS の例
111// $parentDiv は $childP1 を含んでいます。
112compareAndDescribePosition($parentDiv, $childP1, '$parentDiv', '$childP1');
113
114// 例5: DOMDocumentFragment 内のノードとの比較
115// $fragmentP は $fragment に含まれています。
116// DOMDocumentFragment は DOMNode を継承しており、compareDocumentPosition が使えます。
117compareAndDescribePosition($fragmentP, $fragment, '$fragmentP (フラグメント内)', '$fragment');
118
119// 例6: DOMDocumentFragment とメインドキュメントのノードの比較
120// $fragment (およびその中のノード) はまだメインのDOMツリーにアタッチされていないため、
121// $parentDiv とは切断された関係 (DOM_DOCUMENT_POSITION_DISCONNECTED) にあります。
122compareAndDescribePosition($fragment, $parentDiv, '$fragment', '$parentDiv');

このサンプルコードは、PHPのDOM拡張機能を利用して、HTMLやXML文書内の二つのノードがどのような位置関係にあるかを比較する方法を示しています。DOMNode::compareDocumentPosition メソッドは、二つのノードを比較し、その相対的な位置関係を示す整数値を返します。この戻り値は、複数の状態を同時に表すビットマスクであり、ビット演算子 & を用いることで、特定の定数が含まれているかを判定します。

DOM_DOCUMENT_POSITION_CONTAINED_BY 定数は、比較対象のノードが基準となるノードの「内部」に位置する場合に設定されます。例えば、親要素とその子要素を比較する際に、子要素が親要素に含まれている場合にこの定数が検出されます。また、DOM_DOCUMENT_POSITION_PRECEDING 定数は、基準となるノードがドキュメント構造において比較対象のノードよりも「前」に位置する場合を示します。

他にも、基準ノードが比較対象ノードを含んでいることを示す DOM_DOCUMENT_POSITION_CONTAINS、後に位置する DOM_DOCUMENT_POSITION_FOLLOWING、同じノードである DOM_DOCUMENT_POSITION_SAME_NODE、あるいは互いに独立している DOM_DOCUMENT_POSITION_DISCONNECTED といった定数も存在し、これらも同様にビットマスクとして返されます。サンプルコードでは、一時的なノードのコンテナである DOMDocumentFragment 内のノードも含め、様々なノード間の位置関係を具体的に比較し、結果を分かりやすく出力しています。これにより、動的にDOMを操作する際のノード間の関係把握に役立ちます。

このサンプルコードは、PHPのDOM操作においてノード間の位置関係を比較する際に重要な点を示しています。DOMNode::compareDocumentPositionメソッドの戻り値は、複数の状態を同時に表すビットマスクであるため、特定の関係性を判定する際は、単に==で比較するのではなく、定数(例えばDOM_DOCUMENT_POSITION_CONTAINED_BYDOM_DOCUMENT_POSITION_PRECEDING)と&(ビットAND演算子)を用いて判定する必要がある点にご注意ください。また、CONTAINED_BYCONTAINSPRECEDINGFOLLOWINGはそれぞれ逆の関係を示します。DOMDocumentFragmentは、メインのDOMツリーに接続されるまでは独立した存在として扱われ、DOM_DOCUMENT_POSITION_DISCONNECTEDとなることを理解しておきましょう。これらの定数を正しく使うことで、複雑なDOM構造内でのノードの位置を正確に把握できます。

PHP DOMノード包含関係を比較する

1<?php
2
3/**
4 * DOMノード間の包含関係を比較するサンプル関数。
5 *
6 * DOMNode::compareDocumentPosition() メソッドと、
7 * DOMNode::DOCUMENT_POSITION_CONTAINS, DOMNode::DOCUMENT_POSITION_CONTAINED_BY 定数を使用して、
8 * あるノードが別のノードを含むか、または別のノードに含まれているかを判定します。
9 *
10 * システムエンジニアを目指す初心者の方にもわかりやすいように、具体的なHTML構造を例に説明します。
11 */
12function demonstrateDomNodeContainment(): void
13{
14    // 新しいDOMドキュメントを作成し、HTMLコンテンツをロードします。
15    // ここでは、親要素と子要素を持つ簡単なHTML構造を用意します。
16    $dom = new DOMDocument();
17    // loadHTML() は指定されたHTML文字列をパースし、DOMツリーを構築します。
18    $dom->loadHTML('<html><body><div id="parent-container"><p id="child-element">Hello DOM</p></div></body></html>');
19
20    // 比較対象となるノードを取得します。
21    // getElementById() は指定されたIDを持つ要素ノードを返します。
22    $parentNode = $dom->getElementById('parent-container'); // id="parent-container" のdiv要素
23    $childNode = $dom->getElementById('child-element');     // id="child-element" のp要素
24
25    // ノードが正しく取得できたか確認します。
26    if (!$parentNode || !$childNode) {
27        echo "必要なDOMノードが見つかりませんでした。HTML構造を確認してください。" . PHP_EOL;
28        return;
29    }
30
31    echo "--- DOMノードの包含関係の比較 ---" . PHP_EOL;
32    echo "比較対象: 'parent-container' ノード と 'child-element' ノード" . PHP_EOL . PHP_EOL;
33
34    // 1. 'parent-container' ノードから 'child-element' ノードへの位置関係を比較します。
35    // DOMNode::compareDocumentPosition() は、現在のノードと引数で指定されたノードとの位置関係を
36    // 示すビットマスク (整数値) を返します。
37    $positionFromParent = $parentNode->compareDocumentPosition($childNode);
38
39    echo "親ノード (parent-container) から子ノード (child-element) への比較:" . PHP_EOL;
40
41    // DOMNode::DOCUMENT_POSITION_CONTAINS 定数は、
42    // 「現在のノード (parentNode) が引数のノード (childNode) を含む」場合にセットされるビットです。
43    // ビット演算子の '&' を使って、特定のビットが結果に含まれているかを確認します。
44    if (($positionFromParent & DOMNode::DOCUMENT_POSITION_CONTAINS) === DOMNode::DOCUMENT_POSITION_CONTAINS) {
45        echo "  - 'parent-container' ノードは 'child-element' ノードを『含んでいます』。" . PHP_EOL;
46    }
47
48    // DOMNode::DOCUMENT_POSITION_CONTAINED_BY 定数は、
49    // 「現在のノード (parentNode) が引数のノード (childNode) に含まれている」場合にセットされるビットです。
50    // このケースでは parentNode は childNode に含まれていないため、この条件は偽となります。
51    if (($positionFromParent & DOMNode::DOCUMENT_POSITION_CONTAINED_BY) === DOMNode::DOCUMENT_POSITION_CONTAINED_BY) {
52        echo "  - 'parent-container' ノードは 'child-element' ノードに『含まれています』。(この場合は該当しません)" . PHP_EOL;
53    } else {
54        echo "  - 'parent-container' ノードは 'child-element' ノードに『含まれていません』。" . PHP_EOL;
55    }
56
57    echo PHP_EOL;
58
59    // 2. 逆に 'child-element' ノードから 'parent-container' ノードへの位置関係を比較します。
60    $positionFromChild = $childNode->compareDocumentPosition($parentNode);
61
62    echo "子ノード (child-element) から親ノード (parent-container) への比較:" . PHP_EOL;
63
64    // childNode が parentNode を含むことはないので、この条件は偽となります。
65    if (($positionFromChild & DOMNode::DOCUMENT_POSITION_CONTAINS) === DOMNode::DOCUMENT_POSITION_CONTAINS) {
66        echo "  - 'child-element' ノードは 'parent-container' ノードを『含んでいます』。(この場合は該当しません)" . PHP_EOL;
67    } else {
68        echo "  - 'child-element' ノードは 'parent-container' ノードを『含んでいません』。" . PHP_EOL;
69    }
70
71    // childNode は parentNode に含まれているので、この条件は真となります。
72    if (($positionFromChild & DOMNode::DOCUMENT_POSITION_CONTAINED_BY) === DOMNode::DOCUMENT_POSITION_CONTAINED_BY) {
73        echo "  - 'child-element' ノードは 'parent-container' ノードに『含まれています』。" . PHP_EOL;
74    }
75}
76
77// 関数を実行して結果を表示します。
78demonstrateDomNodeContainment();

このサンプルコードは、PHPのDOM拡張機能を用いて、HTMLドキュメント内の要素(ノード)が互いにどのような包含関係にあるかを判定する方法を具体的に示しています。まず、DOMDocumentクラスで簡単なHTMLドキュメントを作成し、親要素と子要素にあたるDOMノードを取得します。

ノード間の位置関係を比較するには、DOMNode::compareDocumentPosition()メソッドを使用します。このメソッドは、呼び出し元のノードと引数で指定されたノードとの位置関係を表すビットマスク(整数値)を戻り値として返します。

リファレンス情報にあるDOMNode::DOCUMENT_POSITION_CONTAINED_BY定数は、compareDocumentPosition()メソッドの結果とビット演算子&を組み合わせることで、「現在のノードが比較対象のノードの子孫として含まれているか」を判定するために利用されます。同様に、DOMNode::DOCUMENT_POSITION_CONTAINS定数は、「現在のノードが比較対象のノードを子孫として含んでいるか」を判定する際に使われます。

コードでは、親ノードから子ノードへの比較と、子ノードから親ノードへの比較の両方を行い、それぞれの定数を使って包含関係の真偽を確かめています。これにより、Webページの構造をプログラムで理解し、要素間の親子関係を正確に把握する基本的な手法を学ぶことができます。

このサンプルコードでは、DOMノード間の親子関係を判定する方法を学べます。まず、HTML文字列を loadHTML() で読み込む際、不正なHTMLはパースエラーの原因となるため注意が必要です。また、getElementById() でノードが取得できなかった場合はnullが返るため、必ず取得結果をチェックしてから操作を進めてください。compareDocumentPosition() メソッドは、現在のノードから引数のノードへの相対的な位置関係をビットマスクとして返します。この戻り値は複数の情報を同時に含む可能性があるため、DOMNode::DOCUMENT_POSITION_CONTAINSDOMNode::DOCUMENT_POSITION_CONTAINED_BY といった定数とビット演算子 & を用いて、特定の関係性が存在するかどうかを正確に判断する必要があります。どちらのノードを基準に比較するかで結果が変わるため、定数の意味を正しく理解し、混同しないように気をつけましょう。これらの定数やメソッドは、多くのDOM要素に共通する DOMNode クラスで利用可能です。

関連コンテンツ

関連IT用語

関連プログラミング言語