【PHP8.x】DOMEntity::DOCUMENT_POSITION_CONTAINED_BY定数の使い方
DOCUMENT_POSITION_CONTAINED_BY定数の使い方について、初心者にもわかりやすく解説します。
基本的な使い方
『DOCUMENT_POSITION_CONTAINED_BY定数は、あるノードが別のノードに内包されている、つまり子孫の関係にあることを示す定数です。この定数は主に、DOMNodeクラスの compareDocumentPosition() メソッドの返り値として利用されます。compareDocumentPosition() メソッドは、HTMLやXMLのような文書構造内における2つのノードの位置関係を比較するためのものです。このメソッドは、比較結果を複数の状態の組み合わせで表現する「ビットマスク」と呼ばれる整数値で返します。DOCUMENT_POSITION_CONTAINED_BYは、そのビットマスクに含まれうる状態の一つです。例えば、ノードAに対して compareDocumentPosition(ノードB) を呼び出した際に、ノードAがノードBの子要素や孫要素である場合、返り値のビットマスクにはこの定数が示すフラグが含まれます。開発者は、返り値とこの定数をビット単位のAND演算子(&)を用いて比較することで、ノードAがノードBに含まれているかどうかを判定できます。このように、DOMツリーにおけるノード間の階層的な包含関係を正確に特定するために重要な役割を果たします。
構文(syntax)
1<?php 2 3echo DOMEntity::DOCUMENT_POSITION_CONTAINED_BY;
引数(parameters)
引数なし
引数はありません
戻り値(return)
int
DOCUMENT_POSITION_CONTAINED_BY は、あるノードが別のノードに含まれていることを示す整数値です。
サンプルコード
DOMノード位置比較 DOCUMENT_POSITION_PRECEDING を表示する
1<?php 2 3/** 4 * 2つのDOMノード間の位置関係を比較し、その結果を人間が読める形式で表示します。 5 * DOMNode::compareDocumentPosition メソッドが返すビットマスクを解析し、 6 * 各定数が示す意味を初心者にも分かりやすく出力します。 7 * 8 * @param DOMNode $node1 比較の基準となるノード (例: $node1->compareDocumentPosition($node2)) 9 * @param DOMNode $node2 比較対象のノード 10 * @param int $result DOMNode::compareDocumentPosition メソッドの戻り値 (ビットマスク) 11 */ 12function displayNodePosition(DOMNode $node1, DOMNode $node2, int $result): void 13{ 14 echo "--- 比較: '{$node1->nodeName}' (基準) と '{$node2->nodeName}' (対象) ---\n"; 15 16 if ($result === 0) { 17 echo " - 両方のノードは同じです (参照元と対象が同じノード)\n"; 18 echo " (DOMNode::compareDocumentPosition が0を返します)\n"; 19 } 20 21 // DOMNode::DOCUMENT_POSITION_DISCONNECTED (0x01) 22 // ノードが同じ文書ツリーに属していない、またはツリーから切り離されている場合 23 if ($result & DOMNode::DOCUMENT_POSITION_DISCONNECTED) { 24 echo " - ノードは切り離されています (DOMNode::DOCUMENT_POSITION_DISCONNECTED)\n"; 25 } 26 27 // DOMNode::DOCUMENT_POSITION_PRECEDING (0x02) - キーワードに関連 28 // 比較対象のノード ($node2) が基準ノード ($node1) よりも文書ツリー内で先行する場合 29 if ($result & DOMNode::DOCUMENT_POSITION_PRECEDING) { 30 echo " - 対象ノード '{$node2->nodeName}' は、基準ノード '{$node1->nodeName}' よりも文書ツリー内で**先行**します。\n"; 31 echo " (DOMNode::DOCUMENT_POSITION_PRECEDING)\n"; 32 } 33 34 // DOMNode::DOCUMENT_POSITION_FOLLOWING (0x04) 35 // 比較対象のノード ($node2) が基準ノード ($node1) よりも文書ツリー内で後続する場合 36 if ($result & DOMNode::DOCUMENT_POSITION_FOLLOWING) { 37 echo " - 対象ノード '{$node2->nodeName}' は、基準ノード '{$node1->nodeName}' よりも文書ツリー内で**後続**します。\n"; 38 echo " (DOMNode::DOCUMENT_POSITION_FOLLOWING)\n"; 39 } 40 41 // DOMNode::DOCUMENT_POSITION_CONTAINS (0x08) 42 // 基準ノード ($node1) が比較対象のノード ($node2) を含んでいる場合 (親-子関係など) 43 if ($result & DOMNode::DOCUMENT_POSITION_CONTAINS) { 44 echo " - 基準ノード '{$node1->nodeName}' は、対象ノード '{$node2->nodeName}' を**含んでいます**。\n"; 45 echo " (DOMNode::DOCUMENT_POSITION_CONTAINS)\n"; 46 } 47 48 // DOMNode::DOCUMENT_POSITION_CONTAINED_BY (0x10) - リファレンス情報に関連 49 // 基準ノード ($node1) が比較対象のノード ($node2) に含められている場合 (子-親関係など) 50 if ($result & DOMNode::DOCUMENT_POSITION_CONTAINED_BY) { 51 echo " - 基準ノード '{$node1->nodeName}' は、対象ノード '{$node2->nodeName}' に**含まれています**。\n"; 52 echo " (DOMNode::DOCUMENT_POSITION_CONTAINED_BY)\n"; 53 } 54 55 // DOMNode::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC (0x20) 56 // 実装固有の比較結果。通常はあまり意識する必要はありません。 57 if ($result & DOMNode::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC) { 58 echo " - 実装固有の比較結果です (DOMNode::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC)\n"; 59 } 60 echo "\n"; 61} 62 63// 1. 新しい DOMDocument オブジェクトを作成します。 64$dom = new DOMDocument('1.0', 'UTF-8'); 65$dom->formatOutput = true; // 出力を整形して見やすくします 66 67// 2. いくつかの要素を作成し、DOMツリーを構築します。 68// 例として、簡単なHTML構造を作成します。 69// <html> 70// <body> 71// <div id="divA"> 72// <p id="p1"><span>スパン1</span></p> 73// </div> 74// <div id="divB"> 75// <p id="p2"></p> 76// </div> 77// </body> 78// </html> 79$html = $dom->createElement('html'); 80$dom->appendChild($html); 81 82$body = $dom->createElement('body'); 83$html->appendChild($body); 84 85$divA = $dom->createElement('div'); 86$divA->setAttribute('id', 'divA'); 87$body->appendChild($divA); 88 89$p1 = $dom->createElement('p'); 90$p1->setAttribute('id', 'p1'); 91$divA->appendChild($p1); 92 93$span1 = $dom->createElement('span', 'スパン1'); 94$p1->appendChild($span1); 95 96$divB = $dom->createElement('div'); 97$divB->setAttribute('id', 'divB'); 98$body->appendChild($divB); 99 100$p2 = $dom->createElement('p'); 101$p2->setAttribute('id', 'p2'); 102$divB->appendChild($p2); 103 104// 3. 比較対象となるノードを取得します。 105$nodeBody = $body; 106$nodeDivA = $divA; 107$nodeP1 = $p1; 108$nodeSpan1 = $span1; 109$nodeDivB = $divB; 110$nodeP2 = $p2; 111 112echo "DOMツリーのノード位置比較の例:\n\n"; 113 114// 4. ノード間の位置関係を比較し、結果を表示します。 115 116// 例1: 親と子の関係 (DOMNode::DOCUMENT_POSITION_CONTAINS と DOMNode::DOCUMENT_POSITION_FOLLOWING) 117// 基準: divA, 対象: p1 118// divAはp1を含んでおり、p1はdivAより後続するため、両方のフラグが立つ 119$result1 = $nodeDivA->compareDocumentPosition($nodeP1); 120displayNodePosition($nodeDivA, $nodeP1, $result1); 121 122// 例2: 子と親の関係 (DOMNode::DOCUMENT_POSITION_CONTAINED_BY と DOMNode::DOCUMENT_POSITION_PRECEDING) 123// 基準: p1, 対象: divA 124// p1はdivAに含まれており、p1はdivAより先行しない (実際にはツリーの深さの関係で先行と判断される場合もあるが、このケースでは含んでいる関係が強い) 125// ここではp1がdivAに含まれている関係を示す DOCUMENT_POSITION_CONTAINED_BY が重要 126$result2 = $nodeP1->compareDocumentPosition($nodeDivA); 127displayNodePosition($nodeP1, $nodeDivA, $result2); 128 129// 例3: 同じ階層の後続ノード (DOMNode::DOCUMENT_POSITION_FOLLOWING) 130// 基準: divA, 対象: divB 131// divBはdivAよりも文書ツリーで後続する 132$result3 = $nodeDivA->compareDocumentPosition($nodeDivB); 133displayNodePosition($nodeDivA, $nodeDivB, $result3); 134 135// 例4: 同じ階層の先行ノード (DOMNode::DOCUMENT_POSITION_PRECEDING) 136// 基準: divB, 対象: divA 137// divAはdivBよりも文書ツリーで先行する 138$result4 = $nodeDivB->compareDocumentPosition($nodeDivA); 139displayNodePosition($nodeDivB, $nodeDivA, $result4); 140 141// 例5: 基準ノードが対象ノードを含み、対象ノードがさらに別のノードに含まれる場合 142// 基準: body, 対象: span1 143// bodyはspan1を含んでおり、span1はbodyよりも後続する 144$result5 = $nodeBody->compareDocumentPosition($nodeSpan1); 145displayNodePosition($nodeBody, $nodeSpan1, $result5); 146 147// 例6: 自身との比較 (0が返される) 148$result6 = $nodeP1->compareDocumentPosition($nodeP1); 149displayNodePosition($nodeP1, $nodeP1, $result6); 150 151?>
PHPのDOM操作において、DOMNode::DOCUMENT_POSITION_CONTAINED_BY は、2つのDOMノード間の位置関係を比較する際に使用される定数の一つです。この定数自体に引数はなく、int 型の値として定義されています。これは、DOMNode::compareDocumentPosition メソッドが返す整数のビットマスクの一部として利用されます。
具体的には、この定数は「比較の基準となるノードが、比較対象のノードに子孫として含まれている」場合に、DOMNode::compareDocumentPosition メソッドの戻り値に含まれるビットが立ちます。例えば、子ノードを基準ノード、その親ノードを比較対象ノードとした場合などに、この定数が結果に含まれます。
サンプルコードの displayNodePosition 関数では、DOMNode::compareDocumentPosition から得られた結果(ビットマスク)と、DOMNode::DOCUMENT_POSITION_CONTAINED_BY 定数をビット論理積 (&) で比較しています。これにより、基準ノードが対象ノードに「含まれている」という関係性が存在するかどうかを判別し、その状況を分かりやすく出力しています。この定数は、DOCUMENT_POSITION_CONTAINS とは逆の親子関係を示す定数であり、文書ツリー内でのノードの詳細な位置関係を把握するために重要です。
DOMNode::compareDocumentPosition メソッドは、2つのDOMノード間の位置関係を数値のビットマスクとして返します。この戻り値は複数の定数(フラグ)が同時に設定される可能性があるため、サンプルコードのようにビットAND演算子(&)を用いて各定数の状態を個別に判定する必要があります。リファレンスにあるDOMNode::DOCUMENT_POSITION_CONTAINED_BYは、基準ノードが比較対象ノードに含まれる関係を示し、DOMNode::DOCUMENT_POSITION_CONTAINSとは逆の関係です。また、キーワードのDOCUMENT_POSITION_PRECEDINGは、比較対象ノードが基準ノードよりも文書ツリー内で先行する場合に立ちます。これらの定数の意味を混同せず、基準と対象ノードのどちらから見た関係であるかを正確に理解することが、DOM操作を正しく行う上で非常に重要です。
DOMノードの包含関係 (document_position_contains) を調べる
1<?php 2 3/** 4 * 2つのDOMノード間の位置関係を比較し、 5 * DOM_DOCUMENT_POSITION_CONTAINED_BY 定数の意味を示す関数。 6 * 7 * この定数は、あるDOMノードが別のDOMノードに包含されている(子孫である) 8 * 関係を判定する際に使用されます。 9 * 10 * @param string $xmlString 比較に使用するXML文字列 11 */ 12function demonstrateDocumentPositionContainedBy(string $xmlString): void 13{ 14 // DOMDocumentオブジェクトを生成し、XML文字列を読み込む 15 $dom = new DOMDocument(); 16 // エラー発生時に警告を出さない設定 17 libxml_use_internal_errors(true); 18 $dom->loadXML($xmlString); 19 libxml_clear_errors(); // エラーをクリア 20 21 // 比較対象のノードを取得 22 // 例: <parent>ノードと<child>ノード 23 $parentNode = $dom->getElementsByTagName('parent')->item(0); 24 $childNode = $dom->getElementsByTagName('child')->item(0); 25 $siblingNode = $dom->getElementsByTagName('sibling')->item(0); 26 27 echo "--- DOMノードの位置関係比較のデモンストレーション ---\n\n"; 28 29 if ($parentNode && $childNode) { 30 // DOMNode::compareDocumentPosition() メソッドは、2つのノード間の相対位置を返します。 31 // 戻り値はビットマスクで、複数の状態を同時に示すことがあります。 32 // 33 // リファレンス情報ではDOMEntity::DOCUMENT_POSITION_CONTAINED_BYとありましたが、 34 // この定数は実際にはDOM拡張機能のグローバル定数 (DOM_DOCUMENT_POSITION_CONTAINED_BY) 35 // またはDOMNodeConstantsクラスの定数として定義されており、 36 // DOMNode::compareDocumentPositionメソッドの戻り値と組み合わせて使用されます。 37 38 // case 1: 親ノードから子ノードを比較 39 // $parentNode->compareDocumentPosition($childNode) は、 40 // 最初のノード ($parentNode) が引数のノード ($childNode) に対して 41 // どのような位置関係にあるかを調べます。 42 // この場合、$parentNodeが$childNodeを「含んでいる」状態です。 43 $positionParentToChild = $parentNode->compareDocumentPosition($childNode); 44 45 echo "比較: 最初のノードが '<parent>'、引数のノードが '<child>'\n"; 46 echo " <parent> は <child> を含んでいますか?\n"; 47 echo " 結果 (ビットマスク): " . sprintf("0x%X", $positionParentToChild) . "\n"; 48 49 if ($positionParentToChild & DOM_DOCUMENT_POSITION_CONTAINS) { 50 echo " - はい、<parent> は <child> を含んでいます (DOM_DOCUMENT_POSITION_CONTAINS)。\n"; 51 echo " これは、最初のノードが引数のノードを包含していることを意味します。\n"; 52 } 53 if ($positionParentToChild & DOM_DOCUMENT_POSITION_CONTAINED_BY) { 54 echo " - いいえ、<parent> は <child> に包含されていません (DOM_DOCUMENT_POSITION_CONTAINED_BY)。\n"; 55 } 56 echo "\n"; 57 58 // case 2: 子ノードから親ノードを比較(DOM_DOCUMENT_POSITION_CONTAINED_BY の主な使用例) 59 // $childNode->compareDocumentPosition($parentNode) は、 60 // 最初のノード ($childNode) が引数のノード ($parentNode) に対して 61 // どのような位置関係にあるかを調べます。 62 // この場合、$childNodeが$parentNodeに「包含されている」状態です。 63 $positionChildToParent = $childNode->compareDocumentPosition($parentNode); 64 echo "比較: 最初のノードが '<child>'、引数のノードが '<parent>'\n"; 65 echo " <child> は <parent> の中に包含されていますか?\n"; 66 echo " 結果 (ビットマスク): " . sprintf("0x%X", $positionChildToParent) . "\n"; 67 68 if ($positionChildToParent & DOM_DOCUMENT_POSITION_CONTAINS) { 69 echo " - いいえ、<child> は <parent> を含んでいません (DOM_DOCUMENT_POSITION_CONTAINS)。\n"; 70 } 71 if ($positionChildToParent & DOM_DOCUMENT_POSITION_CONTAINED_BY) { 72 echo " - はい、<child> は <parent> に包含されています (DOM_DOCUMENT_POSITION_CONTAINED_BY)。\n"; 73 echo " -> これは、最初のノード (<child>) が引数のノード (<parent>) によって包含されている、\n"; 74 echo " つまり <child> が <parent> の子孫ノードであることを示します。\n"; 75 } 76 echo "\n"; 77 } else { 78 echo "比較に必要なDOMノード(<parent>または<child>)が見つかりませんでした。XML構造を確認してください。\n\n"; 79 } 80 81 if ($parentNode && $siblingNode) { 82 // case 3: 兄弟ノード間の比較 83 // 同じ親を持つ兄弟ノード間の比較です。包含関係は持ちません。 84 // $parentNode は $siblingNode の前に位置しています。 85 $positionSiblingComparison = $parentNode->compareDocumentPosition($siblingNode); 86 echo "比較: 最初のノードが '<parent>'、引数のノードが '<sibling>'\n"; 87 echo " 結果 (ビットマスク): " . sprintf("0x%X", $positionSiblingComparison) . "\n"; 88 if ($positionSiblingComparison & DOM_DOCUMENT_POSITION_FOLLOWING) { 89 echo " - はい、<parent> は <sibling> の前に位置しています (DOM_DOCUMENT_POSITION_FOLLOWING)。\n"; 90 echo " これは、最初のノードが引数のノードのドキュメント順で前に来ることを意味します。\n"; 91 } 92 if ($positionSiblingComparison & DOM_DOCUMENT_POSITION_PRECEDING) { 93 echo " - いいえ、<parent> は <sibling> の後に位置していません (DOM_DOCUMENT_POSITION_PRECEDING)。\n"; 94 } 95 if ($positionSiblingComparison & DOM_DOCUMENT_POSITION_CONTAINS) { 96 echo " - いいえ、<parent> は <sibling> を含んでいません (DOM_DOCUMENT_POSITION_CONTAINS)。\n"; 97 } 98 if ($positionSiblingComparison & DOM_DOCUMENT_POSITION_CONTAINED_BY) { 99 echo " - いいえ、<parent> は <sibling> に包含されていません (DOM_DOCUMENT_POSITION_CONTAINED_BY)。\n"; 100 } 101 echo "\n"; 102 } else { 103 echo "比較に必要なDOMノード(<parent>または<sibling>)が見つかりませんでした。XML構造を確認してください。\n\n"; 104 } 105} 106 107// サンプルXMLデータ 108// <parent> と <sibling> は <root> の直接の子であるため、兄弟関係にあります。 109// <child> は <parent> の子です。 110$sampleXml = <<<XML 111<?xml version="1.0" encoding="UTF-8"?> 112<root> 113 <parent id="p1"> 114 <child id="c1">テキスト</child> 115 </parent> 116 <sibling id="s1">別のノード</sibling> 117</root> 118XML; 119 120// 関数を実行 121demonstrateDocumentPositionContainedBy($sampleXml);
このサンプルコードは、PHPのDOM拡張機能を使ってXML文書内のDOMノード間の位置関係を比較する方法と、それに用いられる DOM_DOCUMENT_POSITION_CONTAINED_BY 定数の役割を解説しています。demonstrateDocumentPositionContainedBy 関数は、引数として受け取ったXML文字列を解析し、DOMNode::compareDocumentPosition() メソッドを利用してノード同士の相対位置を判定します。
DOMNode::compareDocumentPosition() メソッドは、二つのノードがどのような関係にあるかを数値(ビットマスク)で返します。この戻り値は、DOM_DOCUMENT_POSITION_CONTAINED_BY のような特定の定数とビット論理積(&)で比較することで、より詳細な位置関係を判定できます。
特に DOM_DOCUMENT_POSITION_CONTAINED_BY 定数は、あるノードが別のノードに「包含されている」、つまり子孫ノードである場合に一致する値を示します。例えば、<child> ノードが <parent> ノードの中に存在するとき、<child> を最初のノードとして <parent> と比較すると、この定数に該当する結果が返されます。これにより、ノードが親要素の子孫であるかを正確に確認することが可能です。コードでは、他にも DOM_DOCUMENT_POSITION_CONTAINS(包含している)や DOM_DOCUMENT_POSITION_FOLLOWING(後に続く)といった定数も比較し、ノード間の多様な位置関係の判定方法を示しています。
この定数DOM_DOCUMENT_POSITION_CONTAINED_BYは、リファレンスにDOMEntityとありますが、実際にはPHPのDOM拡張機能のグローバル定数として利用されます。DOMNode::compareDocumentPosition()メソッドは、ノード間の位置関係をビットマスクとして返すため、特定の関係を判定するには、この定数とビットAND演算子&を組み合わせて使用することが重要です。DOM_DOCUMENT_POSITION_CONTAINED_BYは「最初のノードが引数のノードに包含されている」ことを示し、DOM_DOCUMENT_POSITION_CONTAINSは「最初のノードが引数のノードを包含している」ことを示します。比較するノードの順序で意味が逆になるため注意が必要です。XMLを読み込む際は、libxml_use_internal_errors(true)でエラーを抑制し、libxml_clear_errors()でクリアする処理を入れておくと、予期せぬエラーを防ぎやすくなります。