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

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

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

作成日: 更新日:

基本的な使い方

previousSiblingプロパティは、DOMCharacterDataノードの直前の兄弟ノードを返します。DOMCharacterDataは、テキストデータを含むノード(例えば、テキストノードやコメントノード)を表す抽象クラスです。したがって、このプロパティは、テキストノードやコメントノードから、その直前に位置する兄弟ノードを取得するために使用されます。

具体的には、あるテキストノードに対してpreviousSiblingプロパティを呼び出すと、もし直前に別のノード(例えば、要素ノード、テキストノード、コメントノードなど)が存在すれば、そのノードオブジェクトが返されます。もし直前にノードが存在しない場合、つまり、そのテキストノードが親ノードの最初の子ノードである場合は、nullが返されます。

このプロパティは読み取り専用であり、値を設定することはできません。ノード間の関係を変更するには、DOM APIの他のメソッド(例えば、insertBeforeremoveChildなど)を使用する必要があります。

previousSiblingプロパティを使用することで、DOMツリー構造を辿り、特定のノードの周囲のノードに関する情報を効率的に取得できます。これは、例えば、特定のテキストノードのコンテキストを解析したり、関連する要素ノードの属性を調べたりする際に役立ちます。システムエンジニアがDOMを操作する際、このプロパティは非常に重要な役割を果たします。DOMツリーの構造を理解し、適切に操作することで、Webページのコンテンツを動的に変更したり、データを抽出したりすることが可能になります。

構文(syntax)

1DOMCharacterData::$previousSibling;

引数(parameters)

引数なし

引数はありません

戻り値(return)

DOMNode|null

DOMCharacterData オブジェクトの直前に位置する、同じ親ノードを持つ兄弟ノードを返します。兄弟ノードが存在しない場合は null を返します。

サンプルコード

PHP DOM: previousSibling で直前の兄弟ノードを取得する

1<?php
2
3/**
4 * DOMCharacterData::previousSibling プロパティの動作をデモンストレーションします。
5 *
6 * この関数は、HTML文字列から特定のテキストノードを見つけ、
7 * その直前の兄弟ノード (previousSibling) を取得し、その情報を表示します。
8 * システムエンジニアを目指す初心者でも理解しやすいように、
9 * PHP DOM拡張機能の基本的な操作を示します。
10 */
11function demonstrateDomCharacterDataPreviousSibling(): void
12{
13    // 1. DOMDocument オブジェクトを作成します。
14    // DOMDocumentはHTMLやXMLドキュメントをオブジェクトとして表現するためのクラスです。
15    $dom = new DOMDocument();
16
17    // 2. HTML 文字列を読み込みます。
18    // HTML5のパースエラーを非表示にするため、エラー抑制演算子 (@) を使用しています。
19    // 実際のアプリケーションでは、エラーハンドリングを適切に行うべきです。
20    // ここでは、空白ノードが生成されないようにHTMLを一行で記述しています。
21    // 「ターゲットテキスト。」の直前には「<!-- コメントノード -->」があります。
22    @$dom->loadHTML('<p>前のテキスト。<!-- コメントノード -->ターゲットテキスト。</p>');
23
24    // 3. ターゲットとなる DOMCharacterData (ここでは DOMText) ノードの検索
25    $targetNode = null;
26    // <p> 要素をすべて取得します。
27    $pElements = $dom->getElementsByTagName('p');
28    if ($pElements->length > 0) {
29        // 最初の <p> 要素を取得します。
30        $paragraph = $pElements->item(0);
31
32        if ($paragraph) {
33            // <p> 要素の子ノードをすべてループします。
34            foreach ($paragraph->childNodes as $node) {
35                // ノードが DOMText 型であり、かつその値が「ターゲットテキスト。」であるかを確認します。
36                if ($node instanceof DOMText && $node->nodeValue === 'ターゲットテキスト。') {
37                    $targetNode = $node; // 見つかったノードをターゲットとして設定
38                    break; // ループを終了します
39                }
40            }
41        }
42    }
43
44    // 4. ターゲットノードが見つかった場合の処理
45    if ($targetNode) {
46        echo "--- ターゲットノード情報 ---\n";
47        echo "タイプ: " . get_class($targetNode) . "\n";
48        echo "値: \"" . $targetNode->nodeValue . "\"\n\n";
49
50        // 5. previousSibling プロパティを使用して、直前の兄弟ノードを取得します。
51        // previousSibling は、直前の兄弟ノード (DOMNodeのサブクラス) または、
52        // 直前の兄弟ノードが存在しない場合に null を返します。
53        $previousSibling = $targetNode->previousSibling;
54
55        echo "--- previousSibling 情報 ---\n";
56        if ($previousSibling) {
57            echo "直前の兄弟ノードが見つかりました。\n";
58            echo "タイプ: " . get_class($previousSibling) . "\n";
59            echo "ノード名: " . $previousSibling->nodeName . "\n";
60
61            // 兄弟ノードのタイプに応じて詳細情報を表示します。
62            if ($previousSibling instanceof DOMCharacterData) {
63                // DOMCharacterData (DOMText, DOMComment, DOMCdataSection など) の場合、ノード値を表示
64                echo "値: \"" . $previousSibling->nodeValue . "\"\n";
65            } elseif ($previousSibling instanceof DOMElement) {
66                // DOMElement (例: <span>タグ) の場合、タグ名を表示
67                echo "タグ名: <" . $previousSibling->tagName . ">\n";
68            } else {
69                // その他のノードタイプ
70                echo "詳細な情報は割愛します。\n";
71            }
72        } else {
73            echo "直前の兄弟ノードは見つかりませんでした (nullが返されました)。\n";
74            echo "これは、ターゲットノードが親の最初の子ノードである場合に発生します。\n";
75        }
76    } else {
77        echo "ターゲットノードが見つかりませんでした。HTML構造や検索条件を確認してください。\n";
78    }
79}
80
81// 関数を実行してデモンストレーションを開始します。
82demonstrateDomCharacterDataPreviousSibling();
83

PHPのDOMCharacterData::previousSiblingプロパティは、HTMLやXMLドキュメント内の文字データノード(例:テキストやコメント)から、そのノードの「直前の兄弟ノード」を取得するために使用されます。このプロパティは引数を取らず、戻り値として直前の兄弟ノードを表すDOMNodeオブジェクト、または直前の兄弟ノードが存在しない場合はnullを返します。これにより、ドキュメントツリーにおけるノード間の関係性をプログラムから探索・操作することが可能になります。

提供されたサンプルコードでは、まずDOMDocumentにHTML文字列を読み込み、特定のDOMTextノードである「ターゲットテキスト。」を見つけ出します。次に、この見つけたテキストノードに対しpreviousSiblingプロパティを適用することで、その直前に位置する兄弟ノードを取得しています。コードの実行結果では、取得されたノードがDOMComment(コメントノード)であることが示され、その型や値などの詳細情報が出力されます。このように、previousSiblingプロパティを使うことで、DOMツリーを効果的にたどり、目的のノード周辺の情報を動的に取得できることが理解できます。

サンプルコードではエラー抑制演算子@を使用していますが、これはエラーを隠蔽するためデバッグを困難にし、本番環境では避けるべきです。適切なエラーハンドリングの実装を推奨します。HTMLの記述において改行やインデントはDOMText型の空白ノードとして扱われることがあり、previousSiblingが予期せぬ空白ノードを返す原因となる点に注意が必要です。previousSiblingプロパティは、直前の兄弟ノードが存在しない場合はnullを返しますので、必ずnullチェックを行ってからノードのプロパティにアクセスしてください。また、返されるノードはDOMTextDOMCommentDOMElementなど様々な型があり得ます。取得したノードの型をinstanceofで確認し、型に応じたプロパティ(例:nodeValuetagName)に安全にアクセスすることが重要です。

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

1<?php
2
3/**
4 * DOMCharacterData::previousSibling の使用例を示します。
5 * この関数は、DOMツリー内で特定のノードの直前の兄弟ノードを取得する方法を説明します。
6 *
7 * DOMCharacterData を継承するクラスには、DOMText (テキストノード) や DOMComment (コメントノード) などがあります。
8 */
9function demonstratePreviousSibling(): void
10{
11    // 1. 新しい DOMDocument オブジェクトを作成します。
12    //    XML バージョン 1.0、エンコーディング UTF-8 を指定します。
13    $dom = new DOMDocument('1.0', 'UTF-8');
14    // 出力されるXMLを見やすくするために整形を有効にします。
15    $dom->formatOutput = true;
16
17    // 2. ルート要素を作成し、DOMDocument に追加します。
18    //    例: <container>...</container>
19    $root_element = $dom->createElement('container');
20    $dom->appendChild($root_element);
21
22    // 3. いくつかの異なるタイプのノード(DOMCharacterDataを継承するノードを含む)を作成し、
23    //    ルート要素の子として追加してDOMツリーを構築します。
24    //    DOMツリーの構造イメージ:
25    //    <container>
26    //        <!-- これは最初のコメントです -->
27    //        これはテキスト1です。
28    //        <element>要素ノード</element>
29    //        <!-- これは2番目のコメントです -->
30    //        これはテキスト2です。
31    //    </container>
32
33    $comment1 = $dom->createComment('これは最初のコメントです'); // DOMComment は DOMCharacterData を継承
34    $root_element->appendChild($comment1);
35
36    $text_node1 = $dom->createTextNode('これはテキスト1です。'); // DOMText は DOMCharacterData を継承
37    $root_element->appendChild($text_node1);
38
39    $child_element = $dom->createElement('element', '要素ノード'); // DOMElement
40    $root_element->appendChild($child_element);
41
42    $comment2 = $dom->createComment('これは2番目のコメントです'); // DOMComment は DOMCharacterData を継承
43    $root_element->appendChild($comment2);
44
45    $text_node2 = $dom->createTextNode('これはテキスト2です。'); // DOMText は DOMCharacterData を継承
46    $root_element->appendChild($text_node2);
47
48    echo "--- 構築されたDOMツリー ---" . PHP_EOL;
49    echo $dom->saveXML() . PHP_EOL; // 現在のDOMツリーをXML形式で出力
50
51    echo "--- DOMCharacterData::previousSibling のテスト ---" . PHP_EOL;
52
53    // 4. `text_node2` を対象ノードとして選択します。
54    //    このノードは DOMText クラスのインスタンスであり、DOMCharacterData を継承しています。
55    //    その直前の兄弟ノードは `comment2` (DOMComment) であるはずです。
56    $target_node = $text_node2;
57    echo "現在の対象ノード: '" . $target_node->nodeValue . "'" . PHP_EOL;
58
59    // 5. `previousSibling` プロパティにアクセスして、直前の兄弟ノードを取得します。
60    //    このプロパティは DOMNode オブジェクトを返すか、直前の兄弟ノードが存在しない場合は null を返します。
61    $previous_sibling_node = $target_node->previousSibling;
62
63    // 6. 取得された兄弟ノードが存在するかどうかを確認し、その情報を出力します。
64    if ($previous_sibling_node instanceof DOMNode) {
65        echo "  - 直前の兄弟ノードが見つかりました。" . PHP_EOL;
66        echo "  - ノードタイプ: " . getNodeTypeName($previous_sibling_node->nodeType) . PHP_EOL;
67        // ノード名: テキストノードは #text、コメントノードは #comment、要素ノードはタグ名
68        echo "  - ノード名: '" . $previous_sibling_node->nodeName . "'" . PHP_EOL;
69        // ノード値: テキストノードやコメントノードは内容、要素ノードは空文字列
70        echo "  - ノード値: '" . $previous_sibling_node->nodeValue . "'" . PHP_EOL;
71    } else {
72        echo "  - 対象ノード '" . $target_node->nodeValue . "' には直前の兄弟ノードが存在しません (null を返しました)。" . PHP_EOL;
73    }
74
75    echo PHP_EOL;
76
77    // 別の例: DOMツリーの最初の子ノード (`comment1`) の `previousSibling` を確認します。
78    //         このノードには直前の兄弟ノードが存在しないため、null が返されるはずです。
79    $first_child_node = $comment1;
80    echo "現在の対象ノード (最初の子ノード): '" . $first_child_node->nodeValue . "'" . PHP_EOL;
81    $previous_sibling_of_first = $first_child_node->previousSibling;
82
83    if ($previous_sibling_of_first instanceof DOMNode) {
84        echo "  - 直前の兄弟ノードが見つかりました。" . PHP_EOL;
85        echo "  - ノードタイプ: " . getNodeTypeName($previous_sibling_of_first->nodeType) . PHP_EOL;
86        echo "  - ノード名: '" . $previous_sibling_of_first->nodeName . "'" . PHP_EOL;
87        echo "  - ノード値: '" . $previous_sibling_of_first->nodeValue . "'" . PHP_EOL;
88    } else {
89        echo "  - 対象ノード (最初の子ノード) '" . $first_child_node->nodeValue . "' には直前の兄弟ノードが存在しません (null を返しました)。" . PHP_EOL;
90    }
91}
92
93/**
94 * DOMノードタイプの整数定数を人間が読みやすい文字列に変換するヘルパー関数です。
95 * PHP 8.0 以降で利用可能な `match` 式を使用しています。
96 *
97 * @param int $node_type DOMNode::nodeType プロパティの値
98 * @return string ノードタイプを表す文字列
99 */
100function getNodeTypeName(int $node_type): string
101{
102    return match ($node_type) {
103        DOM_ELEMENT_NODE => 'DOM_ELEMENT_NODE (要素ノード)',
104        DOM_ATTRIBUTE_NODE => 'DOM_ATTRIBUTE_NODE (属性ノード)',
105        DOM_TEXT_NODE => 'DOM_TEXT_NODE (テキストノード)',
106        DOM_CDATA_SECTION_NODE => 'DOM_CDATA_SECTION_NODE (CDATAセクションノード)',
107        DOM_ENTITY_REFERENCE_NODE => 'DOM_ENTITY_REFERENCE_NODE (エンティティ参照ノード)',
108        DOM_ENTITY_NODE => 'DOM_ENTITY_NODE (エンティティノード)',
109        DOM_PROCESSING_INSTRUCTION_NODE => 'DOM_PROCESSING_INSTRUCTION_NODE (処理命令ノード)',
110        DOM_COMMENT_NODE => 'DOM_COMMENT_NODE (コメントノード)',
111        DOM_DOCUMENT_NODE => 'DOM_DOCUMENT_NODE (ドキュメントノード)',
112        DOM_DOCUMENT_TYPE_NODE => 'DOM_DOCUMENT_TYPE_NODE (ドキュメントタイプノード)',
113        DOM_DOCUMENT_FRAGMENT_NODE => 'DOM_DOCUMENT_FRAGMENT_NODE (ドキュメントフラグメントノード)',
114        DOM_NOTATION_NODE => 'DOM_NOTATION_NODE (記法ノード)',
115        default => '不明なノードタイプ',
116    };
117}
118
119// スクリプトの実行を開始します。
120demonstratePreviousSibling();
121

DOMCharacterData::previousSiblingは、XMLやHTMLなどのドキュメントオブジェクトモデル(DOM)ツリーを扱う際に利用されるプロパティです。このプロパティは、DOMCharacterDataクラスを継承するノード、具体的にはテキストノード(DOMText)やコメントノード(DOMComment)などから、自身の直前にある兄弟ノードを取得する際に使用されます。

このプロパティには引数はありません。アクセスすると、現在のノードの直前の兄弟ノードをDOMNodeオブジェクトとして返します。もし直前に兄弟ノードが存在しない場合、このプロパティはnullを返します。これにより、DOMツリー内で特定のノードから前方向へノードをたどる処理を安全に行うことが可能です。

サンプルコードでは、いくつかのノードが追加されたDOMツリーを例に挙げています。「これはテキスト2です。」というテキストノードのpreviousSiblingプロパティにアクセスすると、その直前にある「これは2番目のコメントです」というコメントノードが取得されることが示されています。一方、DOMツリーの最初の子ノードである「これは最初のコメントです」のpreviousSiblingにアクセスした場合は、直前の兄弟ノードが存在しないため、戻り値がnullとなる挙動も確認できます。この機能は、DOM構造を正確に探索し、特定のノードの関係を調べる際に役立ちます。

previousSiblingはプロパティですので、メソッドのように()を付けて呼び出す必要はありません。このプロパティは、対象ノードの直前の兄弟ノードを返しますが、直前の兄弟ノードが存在しない場合はnullを返します。そのため、取得した値を使用する前には、必ずif ($previous_sibling_node instanceof DOMNode)のように、nullではないか、DOMNodeのインスタンスであるかの確認が必要です。特に、ある親要素の最初の子ノードに対してpreviousSiblingを呼び出すと、直前の兄弟ノードが存在しないためnullが返される点にご注意ください。取得したノードの具体的な種類や内容は、nodeTypenodeValueプロパティで確認できます。

関連コンテンツ

関連IT用語

関連プログラミング言語