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

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

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

作成日: 更新日:

基本的な使い方

previousSiblingプロパティは、Dom\HTMLElementクラスのインスタンスが持つ、現在のHTML要素の直前の兄弟ノードを保持するプロパティです。

このプロパティは、HTMLやXMLドキュメントの構造、いわゆるDOMツリー内において、現在の要素の直前に位置する兄弟ノードを取得するために使用されます。兄弟ノードとは、同じ親要素を持つノードのことを指します。例えば、<div><p>最初の段落</p><p>次の段落</p></div>というHTML構造において、2番目の<p>要素から見ると、1番目の<p>要素が直前の兄弟ノードに該当します。

previousSiblingプロパティは、要素ノードだけでなく、テキストノードやコメントノードといった、あらゆる種類のノードを兄弟ノードとして扱います。もし現在の要素の直前に兄弟ノードが存在しない場合は、このプロパティはnullを返します。取得される兄弟ノードは、Dom\Nodeクラスのインスタンスとして返されます。

このプロパティを利用することで、ドキュメントの構造を上方向や横方向に効率的に辿ることが可能になり、特定の要素の前後関係に基づいた操作や情報の取得に役立ちます。HTMLドキュメント内で要素間の相対的な位置関係を探索する際に重要な役割を果たします。

構文(syntax)

1<?php
2
3$document = new Dom\Document();
4$document->loadHTML('<p>前の要素</p><span id="current">現在の要素</span><p>次の要素</p>');
5
6$currentElement = $document->getElementById('current');
7
8if ($currentElement instanceof Dom\HTMLElement) {
9    $previousSiblingNode = $currentElement->previousSibling;
10
11    if ($previousSiblingNode instanceof Dom\Node) {
12        echo $previousSiblingNode->nodeName . "\n";
13        echo $previousSiblingNode->textContent . "\n";
14    }
15}
16
17?>

引数(parameters)

引数なし

引数はありません

戻り値(return)

Dom\Node|null

このプロパティは、現在のDOM要素の直前にある兄弟ノード、または兄弟ノードが存在しない場合はnullを返します。

サンプルコード

PHP Dom\HTMLElement::previousSibling で前の兄弟ノードを取得する

1<?php
2
3/**
4 * 指定されたHTML文字列からIDに基づいて要素を見つけ、その前の兄弟ノードの情報を表示します。
5 *
6 * Dom\HTMLElement::previousSibling は、指定された要素の前の兄弟ノードを返します。
7 * このプロパティは、要素ノードだけでなく、テキストノードやコメントノードなども対象とします。
8 * PHP 8以降のDom拡張は名前空間を使用しています。
9 *
10 * @param string $html HTMLコンテンツ
11 * @param string $id 検索対象の要素のID
12 * @return void
13 */
14function showPreviousSiblingInfo(string $html, string $id): void
15{
16    // DOMDocument オブジェクトを作成し、HTMLをロードします。
17    // LIBXML_HTML_NOIMPLIED と LIBXML_HTML_NODEFDTD は、
18    // HTMLの自動補完(例: DOCTYPE, html, bodyタグの追加)を防ぎます。
19    $dom = new DOMDocument();
20    // エラー抑制演算子 (@) は、HTML5の構文エラーに関する警告を非表示にします。
21    @$dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
22
23    // IDでターゲット要素を検索します。
24    // PHP 8では、DOMElement は Dom\Element のエイリアスとなり、
25    // Dom\Element は Dom\HTMLElement を継承しているため、previousSibling プロパティにアクセスできます。
26    $targetElement = $dom->getElementById($id);
27
28    if ($targetElement === null) {
29        echo "エラー: ID '{$id}' の要素が見つかりません。\n";
30        return;
31    }
32
33    echo "--- ターゲット要素の情報 ---\n";
34    echo "  タグ名: {$targetElement->tagName}\n";
35    echo "  内容: '" . trim($targetElement->nodeValue) . "'\n\n";
36
37    // Dom\HTMLElement::previousSibling プロパティを使用して、前の兄弟ノードを取得します。
38    // 戻り値は Dom\Node オブジェクトか、存在しない場合は null です。
39    $previousNode = $targetElement->previousSibling;
40
41    if ($previousNode === null) {
42        echo "前の兄弟ノードはありません。\n";
43    } else {
44        echo "--- 前の兄弟ノードの情報 ---\n";
45        echo "  ノードタイプ: " . $previousNode->nodeType . " (";
46        // ノードタイプに応じて表示を切り替えます
47        switch ($previousNode->nodeType) {
48            case XML_ELEMENT_NODE:
49                echo "要素ノード";
50                break;
51            case XML_TEXT_NODE:
52                echo "テキストノード";
53                break;
54            case XML_COMMENT_NODE:
55                echo "コメントノード";
56                break;
57            case XML_CDATA_SECTION_NODE:
58                echo "CDATAセクションノード";
59                break;
60            default:
61                echo "その他のノードタイプ";
62        }
63        echo ")\n";
64
65        echo "  ノード名: " . $previousNode->nodeName . "\n";
66        // ノード値は前後の空白や改行を含む場合があるので、trim() で整形して表示します。
67        echo "  ノード値: '" . trim($previousNode->nodeValue) . "'\n";
68
69        // 特定のノードタイプであれば、さらに詳細な情報を表示します。
70        if ($previousNode instanceof Dom\HTMLElement) {
71            echo "  これは Dom\\HTMLElement です (タグ名: {$previousNode->tagName})\n";
72        } elseif ($previousNode instanceof Dom\Text) {
73            echo "  これは Dom\\Text です。\n";
74        } elseif ($previousNode instanceof Dom\Comment) {
75            echo "  これは Dom\\Comment です。\n";
76        }
77    }
78}
79
80// サンプルHTMLコンテンツを定義します。
81// この例では、ターゲット要素の直前にコメントノードとテキストノードが含まれています。
82// HTML内の改行やインデントもテキストノードとして扱われることに注意してください。
83$sampleHtml = <<<HTML
84<!DOCTYPE html>
85<html>
86<body>
87    <div id="container">
88        <!-- これはターゲット要素の直前のコメントです -->
89        <p>最初の要素です</p>
90        
91        テキストノードの例です。
92        <p id="targetElement">これがターゲット要素です。</p>
93        <span>これはターゲット要素の次の要素です。</span>
94    </div>
95</body>
96</html>
97HTML;
98
99// 関数を実行し、結果を出力します。
100showPreviousSiblingInfo($sampleHtml, 'targetElement');
101
102?>

Dom\HTMLElement::previousSiblingは、指定されたHTML要素の直前にある兄弟ノードを取得するためのプロパティです。このプロパティを使用すると、ターゲット要素の前に位置するノードが、HTML要素(例: <p>タグ)だけでなく、空白や改行を含むテキストノード、さらにはコメントノードなども含めて取得できます。

PHP 8で導入された新しいDom拡張では、名前空間Dom\が使われ、Dom\HTMLElementクラスがHTMLの要素を表現します。previousSiblingプロパティは引数を持ちません。戻り値として、前の兄弟ノードが存在すればDom\Nodeオブジェクトを返し、存在しない場合はnullを返します。Dom\Nodeは、要素、テキスト、コメントなど、あらゆる種類のノードの基底クラスです。

このサンプルコードは、与えられたHTML文字列から特定のIDを持つ要素を見つけ出し、その要素の前の兄弟ノードの情報を表示する例です。DOMDocumentオブジェクトにHTMLを読み込み、getElementByIdメソッドでターゲット要素を取得します。その後、$targetElement->previousSiblingプロパティを使って直前の兄弟ノードを取得し、そのノードのタイプや内容などを判別して表示しています。HTMLのインデントや改行もテキストノードとして認識されるため、予期せぬテキストノードが取得される場合があることに注意が必要です。このプロパティは、HTMLの構造を解析し、隣接するコンテンツを操作する際に非常に役立ちます。

previousSiblingプロパティは、対象要素の直前にある要素だけでなく、改行やインデントなどのテキストノード、コメントノードなども兄弟ノードとして返します。もし要素ノードのみを対象としたい場合は、previousElementSiblingプロパティの利用を検討してください。このプロパティの戻り値はノードが見つからない場合にnullとなるため、必ずnullチェックを行い、その後の処理でエラーが発生しないように注意が必要です。PHP 8からはDOM拡張がDom名前空間を使用しており、既存のDOMDocumentなどのクラスとは名前空間での違いがあることを理解しておくと良いでしょう。サンプルコードではloadHTML関数の警告を抑制するために@演算子を使っていますが、これはエラーを隠蔽する行為であるため、実運用では適切なエラーハンドリングを実装することが重要です。取得したノードの具体的なタイプはnodeTypeプロパティやinstanceof演算子で判別し、ノードの種類に応じた処理を行うことで、より堅牢なコードになります。

Dom\HTMLElement::previousSiblingで直前兄弟ノードを取得する

1<?php
2
3/**
4 * Dom\HTMLElement::previousSibling プロパティの使用方法を示すサンプルコードです。
5 *
6 * このプロパティは、現在の要素ノードの直前の兄弟ノード (Dom\Node) を返します。
7 * 直前の兄弟ノードが存在しない場合 (つまり、現在のノードが親の最初の子である場合) は null を返します。
8 * 返されるノードは、要素ノードだけでなく、テキストノードやコメントノードである可能性もあります。
9 */
10function demonstratePreviousSibling(): void
11{
12    // サンプルとなるHTML文字列を定義します。
13    // 改行やインデントもテキストノードとして扱われるため、
14    // 純粋な要素の兄弟関係を明確にするためにHTMLを1行で記述します。
15    $html = <<<HTML
16    <div><p id="first_paragraph">最初の段落</p><span id="target_span">ターゲットのスパン</span><p id="last_paragraph">最後の段落</p></div>
17    HTML;
18
19    // DOMDocumentオブジェクトを初期化し、HTMLをロードします。
20    $dom = new DOMDocument();
21    // HTMLのパースエラーや警告を抑制し、余分なHTMLタグ(<html>, <body>など)の自動挿入を避けます。
22    @$dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
23
24    echo "--- 例1: 直前の兄弟要素が存在する場合 ---\n";
25    // ID 'target_span' を持つ要素を取得します。
26    // PHP 8の新しいDOM拡張では、getElementByIdはDom\HTMLElementのインスタンスを返す可能性があります。
27    $targetElement1 = $dom->getElementById('target_span');
28
29    // ターゲット要素が Dom\HTMLElement のインスタンスであることを確認します。
30    if ($targetElement1 instanceof Dom\HTMLElement) {
31        echo "ターゲット要素: <{$targetElement1->tagName}> '{$targetElement1->textContent}'\n";
32
33        // previousSibling プロパティにアクセスし、直前の兄弟ノードを取得します。
34        $previousSibling1 = $targetElement1->previousSibling;
35
36        if ($previousSibling1 instanceof Dom\HTMLElement) {
37            // 直前の兄弟ノードが Dom\HTMLElement の場合
38            echo "  直前の兄弟要素: <{$previousSibling1->tagName}> '{$previousSibling1->textContent}'\n\n";
39        } elseif ($previousSibling1 instanceof Dom\Node) {
40            // 直前の兄弟ノードが Dom\Node だが HTMLElement ではない場合(例: テキストノード、コメントノード)
41            echo "  直前の兄弟ノード: ノードタイプ '{$previousSibling1->nodeName}' (テキスト: '{$previousSibling1->textContent}')\n\n";
42        } else {
43            // 直前の兄弟ノードが存在しない場合 (null が返された場合)
44            echo "  直前の兄弟ノードはありません。\n\n";
45        }
46    } else {
47        echo "ターゲット要素 'target_span' が見つからないか、Dom\\HTMLElement ではありません。\n\n";
48    }
49
50    echo "--- 例2: 直前の兄弟ノードが存在しない場合 (親の最初の子) ---\n";
51    // ID 'first_paragraph' を持つ要素を取得します。
52    $targetElement2 = $dom->getElementById('first_paragraph');
53
54    // ターゲット要素が Dom\HTMLElement のインスタンスであることを確認します。
55    if ($targetElement2 instanceof Dom\HTMLElement) {
56        echo "ターゲット要素: <{$targetElement2->tagName}> '{$targetElement2->textContent}'\n";
57
58        // previousSibling プロパティにアクセスします。
59        // この要素は親要素 (div) の最初の子なので、直前の兄弟ノードはありません。
60        $previousSibling2 = $targetElement2->previousSibling;
61
62        if ($previousSibling2 instanceof Dom\Node) {
63            echo "  直前の兄弟ノード: ノードタイプ '{$previousSibling2->nodeName}' (テキスト: '{$previousSibling2->textContent}')\n\n";
64        } else {
65            // 期待通り、null が返されます。
66            echo "  直前の兄弟ノードはありません。 (結果: null)\n\n";
67        }
68    } else {
69        echo "ターゲット要素 'first_paragraph' が見つからないか、Dom\\HTMLElement ではありません。\n\n";
70    }
71}
72
73// 関数を実行して、Dom\HTMLElement::previousSibling の動作を確認します。
74demonstratePreviousSibling();

PHPのDom\HTMLElement::previousSiblingプロパティは、HTML要素の操作において、現在の要素の直前に位置する兄弟ノードを取得するために使用されます。兄弟ノードとは、同じ親要素を持つノードのことです。

このプロパティは引数を取りません。戻り値としては、直前の兄弟ノードが存在する場合はDom\Nodeオブジェクトを返します。兄弟ノードが存在しない場合、つまり現在のノードが親要素の最初の子である場合にはnullを返します。ここで返されるDom\Nodeは、HTMLタグで表現される要素ノード(Dom\HTMLElement)だけでなく、改行やインデントといったテキストノード、あるいはコメントノードである可能性もあります。

サンプルコードでは、まずHTML文字列を読み込み、DOMDocumentオブジェクトを作成しています。例1では、<span id="target_span">要素の直前の兄弟ノードを取得しています。この場合、直前には<p id="first_paragraph">要素が存在するため、その要素(Dom\HTMLElement)が取得される様子が示されています。例2では、親要素<div>の最初の子である<p id="first_paragraph">要素の直前の兄弟ノードを取得しようとしています。この要素の直前には兄弟ノードが存在しないため、期待通りnullが返されることが確認できます。このように、previousSiblingプロパティを使うことで、DOMツリー内での要素の前後関係を簡単に辿ることができます。

previousSiblingプロパティは、直前の兄弟ノードを返しますが、これは要素ノードだけでなく、テキストノードやコメントノードである可能性があります。そのため、戻り値がDom\HTMLElement型であるか常にinstanceofで確認し、適切な処理を記述することが重要です。また、直前の兄弟ノードが存在しない場合はnullを返しますので、必ずnullチェックも行ってください。HTMLの改行やインデントもテキストノードとして扱われるため、意図せずテキストノードが返される場合があります。これを避けるには、HTMLを整形せずに1行で記述するか、取得したノードのタイプを確認して要素ノードのみを処理するなどの注意が必要です。サンプルコードで@$dom->loadHTMLにフラグを使用しているのは、HTMLのパースエラーを抑制し、余分な<html><body>タグの自動挿入を防ぐためです。

関連コンテンツ

関連IT用語

関連プログラミング言語