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

【PHP8.x】DOMElement::previousElementSiblingプロパティの使い方

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

作成日: 更新日:

基本的な使い方

previousElementSiblingプロパティは、PHPのDOM拡張機能において、特定のDOMElementオブジェクトの直前の兄弟要素を保持するプロパティです。PHPのDOM拡張機能は、HTMLやXMLなどの構造化された文書をプログラムで操作できるようにするために提供されており、文書の各部分をオブジェクトとして扱います。

DOMElementオブジェクトは、HTMLタグやXMLタグなど、文書内の個々の「要素」を表します。このpreviousElementSiblingプロパティを利用することで、現在対象としているDOMElementオブジェクトの直前に位置する「兄弟要素」を取得することができます。ここで言う兄弟要素とは、同じ親要素を持つ要素のことを指します。例えば、ウェブページの複数の<div>要素が同じ親<body>要素の直下にある場合、ある<div>要素のpreviousElementSiblingプロパティは、その<div>のすぐ前に定義されている<div>要素を返します。

このプロパティは、Webページの構造を解析したり、特定の要素の直前にある別の要素にアクセスして操作したりする際に非常に役立ちます。例えば、特定のHTML要素の前に新しい要素を追加したり、直前の要素の内容に基づいて現在の要素の表示を変更したりするような動的な処理に利用できます。

戻り値は、直前の兄弟要素が存在すればDOMElementオブジェクトとして返されます。しかし、もし対象の要素の直前に兄弟要素が存在しない場合(例えば、その要素が親要素の最初の子要素である場合など)は、nullが返されます。したがって、このプロパティの値を利用する際には、nullでないかどうかの確認を行うことが重要です。

構文(syntax)

1<?php
2$dom = new DOMDocument();
3$dom->loadHTML('<div><span>Element 1</span><p>Element 2</p><span>Element 3</span></div>');
4
5$targetElement = $dom->getElementsByTagName('p')->item(0);
6
7if ($targetElement) {
8    $previousSibling = $targetElement->previousElementSibling;
9
10    if ($previousSibling) {
11        echo "Previous element sibling of <p>: " . $previousSibling->nodeName;
12    } else {
13        echo "No previous element sibling found for <p>.";
14    }
15} else {
16    echo "Target element <p> not found.";
17}

引数(parameters)

引数なし

引数はありません

戻り値(return)

?DOMElement

DOMElementクラスのpreviousElementSiblingプロパティは、現在の要素の直前に存在する兄弟要素をDOMElementオブジェクトとして返します。直前の兄弟要素が存在しない場合はnullを返します。

サンプルコード

DOMElement::previousElementSiblingで直前の要素を取得する

1<?php
2
3/**
4 * DOMElement::previousElementSibling プロパティの動作を実演します。
5 *
6 * このプロパティは、指定された要素の直前の兄弟要素(要素ノードのみ)を返します。
7 * 直前の兄弟要素ノードが存在しない場合は null を返します。
8 */
9function demonstratePreviousElementSibling(): void
10{
11    // サンプルとなるHTML文字列を定義します。
12    // コメントノードやテキストノードは previousElementSibling では無視されます。
13    $html = <<<HTML
14<!DOCTYPE html>
15<html>
16<body>
17    <div id="container">
18        <!-- これはコメントです -->
19        <p>最初のパラグラフ</p>
20        <span>最初のスパン</span>
21        <div>ターゲットDIV</div>
22        <p id="targetParagraph">ターゲットパラグラフ</p>
23        <div>最後のDIV</div>
24    </div>
25</body>
26</html>
27HTML;
28
29    // DOMDocument オブジェクトを作成し、HTMLをロードします。
30    $dom = new DOMDocument();
31    // HTMLのパースエラーを抑制するために @ を使用しますが、
32    // 実際の開発ではエラーハンドリングを適切に行うことが推奨されます。
33    @$dom->loadHTML($html);
34
35    // IDが'targetParagraph'の要素を取得します。
36    $targetElement = $dom->getElementById('targetParagraph');
37
38    if ($targetElement instanceof DOMElement) {
39        echo "ターゲット要素: <{$targetElement->tagName}> (内容: '{$targetElement->textContent}')\n";
40
41        // previousElementSibling プロパティを使用して、直前の兄弟要素(要素ノード)を取得します。
42        // この場合、"ターゲットDIV" の <div> 要素が取得されるはずです。
43        $previousSibling = $targetElement->previousElementSibling;
44
45        if ($previousSibling instanceof DOMElement) {
46            echo "  直前の兄弟要素: <{$previousSibling->tagName}> (内容: '{$previousSibling->textContent}')\n";
47        } else {
48            echo "  ターゲット要素には直前の要素ノードの兄弟要素がありません。\n";
49        }
50
51        echo "\n"; // 区切り線
52
53        // 別の例: コンテナ内の最初の要素の直前の兄弟要素を試します。
54        // ここでは最初の <p> 要素を取得します。
55        // getElementsByTagName() は DOMNodeList を返すため、item(0) で最初の要素を取得します。
56        $firstParagraph = $dom->getElementsByTagName('p')->item(0);
57
58        if ($firstParagraph instanceof DOMElement) {
59            echo "最初のパラグラフ要素: <{$firstParagraph->tagName}> (内容: '{$firstParagraph->textContent}')\n";
60            $previousOfFirstParagraph = $firstParagraph->previousElementSibling;
61
62            // 最初の要素には直前の兄弟要素(要素ノード)がないため、null が返されるはずです。
63            if ($previousOfFirstParagraph instanceof DOMElement) {
64                echo "  直前の兄弟要素: <{$previousOfFirstParagraph->tagName}> (内容: '{$previousOfFirstParagraph->textContent}')\n";
65            } else {
66                echo "  最初のパラグラフ要素には直前の要素ノードの兄弟要素がありません (期待通り null)。\n";
67            }
68        }
69    } else {
70        echo "指定されたIDの要素 ('targetParagraph') が見つかりませんでした。\n";
71    }
72}
73
74// 関数を実行して動作を確認します。
75demonstratePreviousElementSibling();

PHP 8のDOMElement::previousElementSiblingプロパティは、HTMLやXML文書の要素構造を操作する際に利用される便利な機能です。このプロパティは、指定されたDOMElementオブジェクトの直前にある兄弟要素(同じ親要素を持つ要素)を取得するために使用されます。特に重要な点として、このプロパティはコメントノードや単なるテキストノードを無視し、要素ノード(例えば<div><p>といったタグで囲まれた部分)のみを対象としています。

このプロパティには引数を指定する必要がありません。呼び出すだけで直前の兄弟要素を自動的に検索し、その結果を返します。戻り値の型は?DOMElementであり、これは直前の要素ノードが存在する場合にはそのDOMElementオブジェクトを返し、直前に要素ノードが存在しない(例えば、対象の要素が親の最初の子要素である場合や、直前がコメントやテキストノードのみの場合)にはnullを返すことを意味します。

例えば、HTML内で<p id="targetParagraph">という要素があったとして、その直前に<div>要素が存在すれば、previousElementSiblingプロパティはその<div>要素の情報を返します。しかし、もし<p>要素が親の最初の子要素である場合など、直前に要素ノードがない場合はnullが返されるため、プログラムで結果を適切にハンドリングする必要があります。このプロパティを使うことで、DOMツリー内の要素の相対的な位置を効率的に把握し、操作することが可能になります。

DOMElement::previousElementSiblingは、直前の兄弟要素のうちHTMLタグで囲まれた「要素ノード」のみを対象とします。コメントやテキストノード(改行や空白も含む)は無視されるため、見た目上の直前要素と異なる場合があります。直前の要素ノードが存在しない場合はnullを返しますので、取得した値がDOMElementインスタンスであるか、if ($previousSibling instanceof DOMElement)のように必ず型をチェックしてから利用してください。このチェックを怠ると、nullに対してプロパティにアクセスしようとしてエラー(Fatal error)が発生する危険性があります。また、サンプルコードにある@演算子によるエラー抑制は、実際の開発では推奨されません。HTMLのパースエラーは、適切にエラーハンドリングを行うべきです。

PHP DOMElement::previousElementSiblingで直前要素を取得する

1<?php
2
3/**
4 * DOMElement::previousElementSibling プロパティの使用例を示します。
5 * JavaScriptのpreviousElementSiblingと同様に、現在の要素の直前の要素ノード(テキストノードやコメントノードはスキップ)を取得します。
6 *
7 * @return void
8 */
9function demonstratePreviousElementSibling(): void
10{
11    // 1. DOMDocument オブジェクトを作成し、HTMLを読み込みます。
12    $dom = new DOMDocument();
13
14    // サンプルHTML文字列を定義します。
15    $html = <<<HTML
16    <div id="container">
17        <p>最初の兄弟要素 (P)</p>
18        <!-- これはコメントです -->
19        テキストノード
20        <span>ターゲット要素 (SPAN)</span>
21        <div>次の兄弟要素 (DIV)</div>
22    </div>
23    HTML;
24
25    // HTMLを読み込みます。
26    // LIBXML_HTML_NOIMPLIED と LIBXML_HTML_NODEFDTD フラグは、
27    // 不要な<html><body>タグの自動追加を防ぎ、よりシンプルなDOMツリーを構築します。
28    $dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
29
30    // 2. DOMXPath を使用して、目的の要素を取得します。
31    $xpath = new DOMXPath($dom);
32
33    // <span>要素をターゲットとして取得します。
34    $targetSpanElement = $xpath->query('//span')->item(0);
35
36    if ($targetSpanElement instanceof DOMElement) {
37        echo "--- ターゲット要素が<span>の場合 ---\n";
38        echo "ターゲット要素: " . $targetSpanElement->tagName . " (内容: " . trim($targetSpanElement->textContent) . ")\n";
39
40        // 3. previousElementSibling プロパティを使用して、直前の要素ノードを取得します。
41        // テキストノードやコメントノードはスキップされ、直前の要素ノード(この場合は<p>)が取得されます。
42        $previousElementOfSpan = $targetSpanElement->previousElementSibling;
43
44        if ($previousElementOfSpan instanceof DOMElement) {
45            echo "直前の要素兄弟: " . $previousElementOfSpan->tagName . " (内容: " . trim($previousElementOfSpan->textContent) . ")\n";
46        } else {
47            echo "直前の要素兄弟は見つかりませんでした。\n";
48        }
49        echo "\n";
50    } else {
51        echo "ターゲット要素(<span>)が見つかりませんでした。\n";
52    }
53
54    // 4. 最初の要素の場合の previousElementSibling を確認します。
55    // <p>要素(DOMツリーにおける最初の兄弟要素)をターゲットとして取得します。
56    $firstParagraphElement = $xpath->query('//p')->item(0);
57    if ($firstParagraphElement instanceof DOMElement) {
58        echo "--- ターゲット要素が<p>(最初の要素)の場合 ---\n";
59        echo "ターゲット要素: " . $firstParagraphElement->tagName . " (内容: " . trim($firstParagraphElement->textContent) . ")\n";
60
61        // 最初の要素にはそれより前の要素がないため、previousElementSibling は null を返します。
62        $previousElementOfParagraph = $firstParagraphElement->previousElementSibling;
63
64        if ($previousElementOfParagraph instanceof DOMElement) {
65            echo "直前の要素兄弟: " . $previousElementOfParagraph->tagName . " (このケースでは通常発生しません)\n";
66        } else {
67            echo "直前の要素兄弟は見つかりませんでした (最初の要素のため期待通りNULL)。\n";
68        }
69        echo "\n";
70    } else {
71        echo "最初の要素(<p>)が見つかりませんでした。\n";
72    }
73}
74
75// 関数を実行して、previousElementSibling の動作を確認します。
76demonstratePreviousElementSibling();
77
78?>

DOMElement::previousElementSiblingは、PHPでHTMLやXMLの文書構造(DOMツリー)を操作する際に、現在の要素の直前にある「兄弟要素ノード」を取得するためのプロパティです。このプロパティの大きな特徴は、テキストノードやコメントノードといった要素以外のノードを無視し、純粋なHTML要素(タグ)のみを対象とする点にあります。この動作は、JavaScriptのpreviousElementSiblingと全く同じです。

このプロパティには引数はなく、現在の要素の直前に要素が存在すれば、そのDOMElementオブジェクトを戻り値として返します。もし直前の要素が見つからない場合、例えば現在の要素が親要素内の最初の兄弟要素である場合はnullを返します。

サンプルコードでは、まずHTMLを読み込み、<span>要素をターゲットとしています。この<span>の直前にはコメントやテキストノードがありますが、previousElementSiblingはそれらをスキップし、直前の<p>要素を正確に取得する様子を示しています。また、親要素内で最も最初の兄弟要素である<p>に対してpreviousElementSiblingを適用した場合は、直前に要素が存在しないため期待通りnullが返されることも確認できます。これにより、DOMツリー内の要素間の関係を効率的にたどることができます。

DOMElement::previousElementSiblingは、現在の要素の直前にある「要素ノード」のみを取得します。テキストノードやコメントノードはスキップされるため、DOMツリー上で物理的にすぐ隣にあるものではなく、HTMLタグで構成された要素を対象とすることをご理解ください。

直前の要素が見つからない場合(例えば、ターゲット要素が親要素の最初の子要素である場合など)はnullを返します。そのため、取得した結果をif ($result instanceof DOMElement)のように必ずチェックし、nullでないことを確認してから操作を行うようにしてください。このチェックを怠ると、予期せぬエラーにつながる可能性があります。

また、DOMDocumentDOMXPathを組み合わせることで、PHPでHTMLを効率的にパースし、目的の要素を柔軟に検索できます。loadHTML関数のLIBXML_HTML_NOIMPLIEDLIBXML_HTML_NODEFDTDといったオプションフラグは、自動挿入されるHTMLタグを制御し、よりシンプルなDOMツリーを構築するのに役立ちます。

関連コンテンツ

関連プログラミング言語