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

【PHP8.x】DOMText::previousSiblingプロパティの使い方

previousSiblingプロパティの使い方について、初心者にもわかりやすく解説します。

作成日: 更新日:

基本的な使い方

previousSiblingプロパティは、PHPのDOM拡張機能において、DOMTextクラスのインスタンスが保持する、現在のテキストノードの直前にある兄弟ノードを保持するプロパティです。このプロパティは、HTMLやXMLのような文書の構造を表すDOMツリー内を移動し、特定のノードの前後関係を把握する際に利用されます。

DOMにおける兄弟ノードとは、同じ親要素を持つノードのことを指します。例えば、ある段落の中に複数のテキストや要素が存在する場合、それらは互いに兄弟の関係にあります。previousSiblingプロパティは、この関係性の中で、現在対象としているDOMTextノードの直前に位置する兄弟ノードを取得するために使用されます。

このプロパティが返す値は、DOMNode型のオブジェクトです。返されるノードは、要素ノード(DOMElement)、テキストノード(DOMText)、コメントノード(DOMComment)など、様々な種類のノードである可能性があります。もし、現在のDOMTextノードの直前に兄弟ノードが存在しない場合、このプロパティはnullを返します。

システムエンジニアを目指す方にとって、文書構造をプログラムで操作する能力は非常に重要です。previousSiblingプロパティを理解することで、ウェブサイトのコンテンツを動的に解析したり、特定のテキストの前にある要素や情報を取得したりする処理を効率的に記述できるようになります。これにより、DOMツリーの探索や操作の柔軟性が大きく向上し、より複雑なデータ処理や動的なコンテンツ生成が可能になります。

構文(syntax)

1<?php
2$dom = new DOMDocument();
3$element = $dom->createElement('parent');
4$dom->appendChild($element);
5
6$childElement = $dom->createElement('child');
7$element->appendChild($childElement);
8
9$textNode = $dom->createTextNode('Hello');
10$element->appendChild($textNode);
11
12$previousSiblingNode = $textNode->previousSibling;
13?>

引数(parameters)

引数なし

引数はありません

戻り値(return)

?DOMNode

DOMTextノードの直前の兄弟ノードであるDOMNode、または直前に兄弟ノードがない場合はnullを返します。

サンプルコード

PHP DOMText::previousSibling で前の要素を取得する

1<?php
2
3/**
4 * Demonstrates how to use DOMText::previousSibling to find the immediately preceding sibling node.
5 *
6 * This function creates a simple HTML structure, navigates to specific DOMText nodes,
7 * and then retrieves their previous sibling nodes, printing relevant information.
8 *
9 * For system engineers, understanding DOM traversal (like finding siblings) is crucial
10 * for tasks such as parsing HTML/XML documents, web scraping, or manipulating document
11 * structures programmatically in PHP.
12 */
13function demonstrateDomTextPreviousSibling(): void
14{
15    // 1. Create a new DOMDocument instance.
16    //    This object will represent the entire HTML document.
17    $dom = new DOMDocument();
18
19    // Load a simple HTML string into the DOMDocument.
20    // Elements and text nodes are placed contiguously to clearly define their
21    // sibling relationships without accidental whitespace text nodes from formatting.
22    $htmlContent = '<div><span>Item A</span>A text node.<b>Item B</b>Another text node.</div>';
23    $dom->loadHTML($htmlContent);
24
25    // 2. Access the <div> element. This is where our target nodes reside.
26    //    getElementsByTagName returns a DOMNodeList, so we get the first (and only) 'div'.
27    $divElement = $dom->getElementsByTagName('div')[0];
28
29    // The child nodes of $divElement are structured as follows:
30    // [0] DOMElement: <span>Item A</span>
31    // [1] DOMText: "A text node."
32    // [2] DOMElement: <b>Item B</b>
33    // [3] DOMText: "Another text node."
34
35    echo "--- Demonstrating previousSibling for 'Another text node.' ---\n";
36
37    // 3. Target the DOMText node "Another text node." (which is childNodes item at index 3).
38    $targetTextNode1 = $divElement->childNodes->item(3);
39
40    // Ensure the retrieved node is indeed a DOMText instance before proceeding.
41    if ($targetTextNode1 instanceof DOMText) {
42        echo "Target DOMText node content: '" . $targetTextNode1->nodeValue . "'\n";
43
44        // Access the previousSibling property.
45        // This property returns the node immediately preceding this node, or null if none exists.
46        $previousSibling = $targetTextNode1->previousSibling;
47
48        // Check if a previous sibling was found (the return type is ?DOMNode).
49        if ($previousSibling instanceof DOMNode) {
50            echo "  Previous sibling found:\n";
51            echo "    Node Name: " . $previousSibling->nodeName . "\n";
52            echo "    Node Type: ";
53            // Use DOMNode constants for clearer type identification.
54            switch ($previousSibling->nodeType) {
55                case XML_ELEMENT_NODE:
56                    echo "ELEMENT_NODE"; // e.g., <div>, <span>, <b>
57                    break;
58                case XML_TEXT_NODE:
59                    echo "TEXT_NODE";    // e.g., "Some text"
60                    break;
61                case XML_COMMENT_NODE:
62                    echo "COMMENT_NODE"; // e.g., <!-- comment -->
63                    break;
64                default:
65                    echo "OTHER_NODE (" . $previousSibling->nodeType . ")";
66                    break;
67            }
68            echo "\n";
69            // nodeValue holds the text content for DOMText, or concatenated text for DOMElement.
70            echo "    Node Value: '" . $previousSibling->nodeValue . "'\n";
71            // If it's an element, printing its outer HTML can be very descriptive.
72            if ($previousSibling instanceof DOMElement) {
73                echo "    Outer HTML (for Element): " . $dom->saveHTML($previousSibling) . "\n";
74            }
75        } else {
76            echo "  No previous sibling found for the target text node.\n";
77        }
78    } else {
79        echo "Error: Could not find the expected DOMText node ('Another text node.') or it's not a DOMText instance.\n";
80    }
81
82    echo "\n--- Demonstrating previousSibling for 'A text node.' ---\n";
83
84    // 4. Target another DOMText node "A text node." (which is childNodes item at index 1).
85    $targetTextNode2 = $divElement->childNodes->item(1);
86
87    if ($targetTextNode2 instanceof DOMText) {
88        echo "Target DOMText node content: '" . $targetTextNode2->nodeValue . "'\n";
89
90        $previousSibling2 = $targetTextNode2->previousSibling;
91
92        if ($previousSibling2 instanceof DOMNode) {
93            echo "  Previous sibling found:\n";
94            echo "    Node Name: " . $previousSibling2->nodeName . "\n";
95            echo "    Node Type: ";
96            switch ($previousSibling2->nodeType) {
97                case XML_ELEMENT_NODE:
98                    echo "ELEMENT_NODE";
99                    break;
100                case XML_TEXT_NODE:
101                    echo "TEXT_NODE";
102                    break;
103                case XML_COMMENT_NODE:
104                    echo "COMMENT_NODE";
105                    break;
106                default:
107                    echo "OTHER_NODE (" . $previousSibling2->nodeType . ")";
108                    break;
109            }
110            echo "\n";
111            echo "    Node Value: '" . $previousSibling2->nodeValue . "'\n";
112            if ($previousSibling2 instanceof DOMElement) {
113                echo "    Outer HTML (for Element): " . $dom->saveHTML($previousSibling2) . "\n";
114            }
115        } else {
116            echo "  No previous sibling found for the target text node.\n";
117        }
118    } else {
119        echo "Error: Could not find the expected DOMText node ('A text node.') or it's not a DOMText instance.\n";
120    }
121}
122
123// Execute the demonstration function when the script is run.
124demonstrateDomTextPreviousSibling();

PHPのDOMTextクラスが提供するpreviousSiblingプロパティは、HTMLやXML文書のDOMツリーにおいて、現在のテキストノードの直前に位置する兄弟ノードを取得するために使用されます。このプロパティは引数を必要とせず、現在のノードの直前の兄弟ノードが存在すればそのDOMNodeオブジェクトを返します。もし直前の兄弟ノードが存在しない場合はnullを返します。戻り値の型は?DOMNodeです。

システムエンジニアにとって、HTMLやXML文書のDOMツリー構造を理解し、要素間を効率的に移動することは、Webスクレイピングやプログラムによる文書操作において不可欠です。このプロパティは、特定のテキスト内容の前後関係を調べたり、隣接する要素に基づいてDOMを操作したりする際に特に有用です。

サンプルコードでは、まずシンプルなHTML構造を持つDOMツリーを構築しています。そして、<div>要素内の特定のテキストノードを対象に選び、そのpreviousSiblingプロパティを使用して直前の兄弟ノード(例えば、テキストノード「Another text node.」の直前の<b>Item B</b>要素など)を正確に取得し、その情報(ノード名、タイプ、値など)を表示する過程を示しています。これにより、DOMツリー内でのノード間の関係と、その探索方法を具体的に理解することができます。

DOMText::previousSiblingは、前の兄弟ノードが存在しない場合にnullを返します。そのため、取得した値がnullでないか、instanceof DOMNodeで必ず確認してから利用してください。HTMLをDOMDocumentに読み込む際、要素間の改行やスペースも空白のテキストノードとして扱われる場合があります。この場合、意図しないテキストノードが前の兄弟として検出される可能性があるため、注意が必要です。このプロパティはDOMTextだけでなく、DOMElementなどDOMNodeを継承するクラスでも利用できますので、取得したノードのnodeTypeを確認し、適切な処理を行うことをお勧めします。

DOMText::previousSiblingで前の兄弟ノードを取得する

1<?php
2
3/**
4 * DOMText::previousSibling プロパティの使用例を示します。
5 * HTMLドキュメントから特定のテキストノードを見つけ、その前の兄弟ノードを表示します。
6 *
7 * この関数は、DOMDocumentとDOMノードの基本的な操作、特に兄弟ノードへのアクセス方法を
8 * システムエンジニアを目指す初心者向けに簡潔に説明します。
9 */
10function demonstrateDomTextPreviousSibling(): void
11{
12    // 処理対象となるHTML文字列を定義します。
13    // ここでは、「テキストノード」の前の兄弟がコメントノードである例を示します。
14    $html = <<<HTML
15    <div>
16        <span>最初の要素</span>
17        <!-- コメントノード -->
18        テキストノード
19        <p>次の要素</p>
20    </div>
21    HTML;
22
23    // DOMDocumentオブジェクトを新しく作成します。
24    $dom = new DOMDocument();
25    
26    // HTMLの読み込み中に発生する警告やエラーを一時的に抑制します。
27    // 実際のアプリケーションでは、エラーハンドリングを適切に行うことが推奨されます。
28    libxml_use_internal_errors(true);
29    
30    // HTML文字列をDOMDocumentにロードします。
31    $dom->loadHTML($html);
32    
33    // 抑制したエラー情報をクリアします。
34    libxml_clear_errors();
35
36    // HTML内の最初の `div` 要素を取得します。
37    // `getElementsByTagName` は、指定されたタグ名を持つすべての要素のリストを返します。
38    // `item(0)` はそのリストの最初の要素を取得します。
39    $divElement = $dom->getElementsByTagName('div')->item(0);
40
41    // `div` 要素が見つからなかった場合の処理です。
42    if ($divElement === null) {
43        echo "HTML内の'div'要素が見つかりませんでした。\n";
44        return;
45    }
46
47    // 対象となるテキストノード「テキストノード」を探します。
48    // `childNodes` プロパティは、要素のすべての子ノード(要素、テキスト、コメントなど)のリストを含みます。
49    $targetTextNode = null;
50    foreach ($divElement->childNodes as $node) {
51        // ノードが `DOMText` のインスタンス(つまりテキストノード)であり、
52        // かつその内容が「テキストノード」であるかチェックします。
53        // `trim()` は、ノード値の前後の空白(改行やインデントなど)を除去するために使用します。
54        if ($node instanceof DOMText && trim($node->nodeValue) === 'テキストノード') {
55            $targetTextNode = $node;
56            break; // 目的のノードが見つかったのでループを終了します。
57        }
58    }
59
60    // 対象のテキストノードが見つからなかった場合の処理です。
61    if ($targetTextNode === null) {
62        echo "対象のテキストノード 'テキストノード' が見つかりませんでした。\n";
63        return;
64    }
65
66    echo "対象のテキストノード: '" . trim($targetTextNode->nodeValue) . "'\n\n";
67
68    // `previousSibling` プロパティを使用して、現在のテキストノードの直前の兄弟ノードを取得します。
69    // 兄弟ノードが存在しない場合は `null` が返されます。
70    $previousSibling = $targetTextNode->previousSibling;
71
72    // 取得した前の兄弟ノードが存在するかどうかを確認します。
73    if ($previousSibling !== null) {
74        echo "前の兄弟ノードが見つかりました。\n";
75        // ノードの名前(例: div, span, #text, #comment)とタイプIDを表示します。
76        // `#text` はテキストノード、`#comment` はコメントノードを表します。
77        echo "  ノード名: " . $previousSibling->nodeName . " (タイプID: " . $previousSibling->nodeType . ")\n";
78
79        // ノードの具体的なタイプに応じて、より詳細な情報を表示します。
80        if ($previousSibling instanceof DOMElement) {
81            echo "  これは要素ノードです。タグ名: " . $previousSibling->tagName . ", 内容: " . trim($previousSibling->textContent) . "\n";
82        } elseif ($previousSibling instanceof DOMComment) {
83            echo "  これはコメントノードです。内容: " . $previousSibling->nodeValue . "\n";
84        } elseif ($previousSibling instanceof DOMText) {
85            echo "  これはテキストノードです。内容: '" . trim($previousSibling->nodeValue) . "'\n";
86        } else {
87            // その他のノードタイプ(例: DOMCdataSection, DOMProcessingInstructionなど)
88            echo "  これはその他のノードタイプです。値: '" . trim($previousSibling->nodeValue) . "'\n";
89        }
90    } else {
91        echo "前の兄弟ノードは見つかりませんでした。\n";
92    }
93}
94
95// 関数を実行してサンプルコードの動作を確認します。
96demonstrateDomTextPreviousSibling();
97
98?>

DOMText::previousSiblingプロパティは、PHP 8のDOM拡張機能において、現在のテキストノードの直前に位置する兄弟ノードを取得するために使用されます。このプロパティは引数を一切取らず、現在のテキストノードと同じ親を持つ、直前の兄弟ノードを返します。戻り値は?DOMNode型であり、直前の兄弟ノードが存在する場合はDOMNodeオブジェクトが返されますが、存在しない場合はnullを返します。

サンプルコードでは、まずHTML文字列をDOMDocumentクラスで読み込み、解析しています。次に、HTML内の特定のテキストノード「テキストノード」を検索し、そのDOMTextインスタンスを見つけ出します。見つかったテキストノードに対してpreviousSiblingプロパティを使用することで、その直前にある兄弟ノードを取得しています。この例では、コメントノードが「テキストノード」の直前の兄弟として配置されており、そのノードの種別や内容が正確に表示されることを確認できます。このプロパティは、HTMLやXMLドキュメントの構造を分析したり、特定のノードを基準として前後の要素を操作したりする際に非常に役立ちます。

previousSiblingプロパティは、直前の兄弟ノードが存在しない場合にnullを返しますので、取得後には必ずnullチェックを行ってください。HTMLの解析では、要素間の改行やインデントなどの空白もDOMTextノードとして扱われることがあり、直前の要素ノードを期待している場合でも、間に空白ノードが挟まっている可能性に注意が必要です。返されるノードは汎用的なDOMNode型ですので、instanceof演算子で実際のノードタイプ(DOMElementDOMCommentDOMTextなど)を確認し、適切なプロパティを利用してください。また、DOMDocument::loadHTMLによるHTML読み込み時には、不正なマークアップによるエラーに備え、適切なエラーハンドリングを検討してください。

関連コンテンツ

関連IT用語

関連プログラミング言語