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

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

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

作成日: 更新日:

基本的な使い方

Dom\TextクラスのpreviousSiblingプロパティは、現在のノードの直前の兄弟ノードを表すプロパティです。具体的には、テキストノード(Dom\Textオブジェクト)において、そのノードと同じ親ノードを持ち、かつそのノードよりも前に位置するノードを取得するために使用されます。もし直前の兄弟ノードが存在しない場合、このプロパティはnullを返します。

このプロパティは読み取り専用であり、値を設定することはできません。ノード間の関係性を辿る際に非常に役立ち、例えば、特定のテキストノードの前にどのような要素やテキストが存在するかを調べることができます。XMLやHTMLドキュメントを解析し、特定のテキストノードの文脈を理解したり、構造的な情報を取得したりする際に利用できます。

previousSiblingプロパティを使用することで、DOMツリーをナビゲートし、特定のテキストノードに関連する他のノードを効率的に特定することができます。例えば、特定のテキストノードを含む要素の属性値を調べたり、テキストノードの前にあるコメントノードの内容を確認したりする処理などが可能です。DOM操作において、ノード間の相対的な位置関係に基づいて処理を分岐させたい場合に有効活用できるプロパティです。

構文(syntax)

1Dom\Text::$previousSibling;

引数(parameters)

引数なし

引数はありません

戻り値(return)

Dom\Node|null

このプロパティは、現在のテキストノードの直前に位置する兄弟ノードを返します。兄弟ノードが存在しない場合は null を返します。

サンプルコード

PHP Dom\Text previousSibling を取得する

1<?php
2
3/**
4 * HTML文字列から特定のDom\Textノードの直前の兄弟ノードを取得し表示する関数。
5 *
6 * この関数は、PHP 8で導入されたDom\TextクラスのpreviousSiblingプロパティの使用例を示します。
7 * 従来のDOMDocumentと新しいDom名前空間のクラスを組み合わせて使用します。
8 * システムエンジニアを目指す初心者でも理解しやすいように、各ステップをコメントで説明しています。
9 */
10function demonstrateDomTextPreviousSibling(): void
11{
12    // 1. ターゲットとなるDom\Textノードを含むHTML文字列を定義します。
13    // ここでは " World" (スペースとWorld) がテキストノードとして扱われ、
14    // その直前の兄弟ノードは <span> 要素になることを意図しています。
15    $html = '<div><span>Hello</span> World<p>PHP</p></div>';
16
17    echo "元のHTMLコンテンツ:\n";
18    echo $html . "\n\n";
19
20    // 2. DOMDocumentオブジェクトを作成し、HTMLをロードします。
21    // DOMDocumentは従来のDOM拡張であり、デフォルトでDOMNodeやDOMTextを生成します。
22    $dom = new DOMDocument();
23    // loadHTMLはHTML文字列を解析し、DOMツリーを構築します。
24    // 余分な<html>, <body>タグは自動的に追加されますが、このサンプルの機能には影響しません。
25    $dom->loadHTML($html);
26
27    // 3. 目的の<div>要素を取得します。
28    // getElementsByTagNameは指定されたタグ名を持つ要素のリストを返します。
29    // item(0)で最初の要素を取得します。
30    $divElement = $dom->getElementsByTagName('div')->item(0);
31
32    if (!$divElement) {
33        echo "エラー: 'div' 要素が見つかりません。\n";
34        return;
35    }
36
37    // 4. ターゲットとなるDOMTextノードを見つけます。
38    // この例では、親要素の子ノードをループして " World" というテキストノードを探します。
39    $targetDomTextNode = null;
40    foreach ($divElement->childNodes as $node) {
41        // ノードがDOMTextクラスのインスタンスであり、かつ内容が " World" であるか確認します。
42        if ($node instanceof DOMText && $node->nodeValue === ' World') {
43            $targetDomTextNode = $node;
44            break;
45        }
46    }
47
48    if (!$targetDomTextNode) {
49        echo "エラー: ' World' というテキストノードが見つかりません。\n";
50        return;
51    }
52
53    echo "--- ターゲットとなるノード --- \n";
54    echo "ノードの種類 (従来のDOMText): '" . $targetDomTextNode->nodeName . "'\n";
55    echo "ノードの値: '" . $targetDomTextNode->nodeValue . "'\n\n";
56
57    // 5. 従来のDOMTextノードをPHP 8の新しいDom\Textオブジェクトに変換します。
58    // Dom\Text::createFromNode() は、従来のDOMNodeオブジェクトから新しいDom名前空間の
59    // オブジェクト(ここではDom\Text)を作成するために使用されます。
60    // これにより、PHP 8で導入されたDom名前空間のプロパティやメソッドにアクセスできます。
61    $domTextNode = Dom\Text::createFromNode($targetDomTextNode);
62
63    echo "Dom\\Textオブジェクトに変換しました。\n\n";
64
65    // 6. Dom\Text::previousSibling プロパティを使用して直前の兄弟ノードを取得します。
66    // このプロパティは、現在のノードの直前にある兄弟ノードを返します。
67    // 兄弟ノードが存在しない場合は null を返します。戻り値は Dom\Node または null です。
68    $previousSibling = $domTextNode->previousSibling;
69
70    echo "--- previousSibling の情報 --- \n";
71    if ($previousSibling) {
72        echo "直前の兄弟ノードが見つかりました。\n";
73        echo "ノード名: " . $previousSibling->nodeName . "\n";
74        // nodeTypeはノードの種類を示す数値です (例: 1=要素ノード, 3=テキストノード, 8=コメントノード)。
75        echo "ノードの種類 (数値): " . $previousSibling->nodeType . "\n";
76        echo "ノードの値: '" . $previousSibling->nodeValue . "'\n";
77
78        // 取得した兄弟ノードがどのようなタイプかを確認し、詳細な情報を表示します。
79        if ($previousSibling instanceof Dom\Element) {
80            echo "これはDom\\Element (要素ノード) です。\n";
81            // 要素ノードの場合、textContentはその要素とその全ての子孫のテキスト内容を返します。
82            echo "テキストコンテンツ: '" . $previousSibling->textContent . "'\n";
83            echo "期待される結果: 'span'要素で、そのテキストコンテンツは 'Hello'\n";
84        } elseif ($previousSibling instanceof Dom\Text) {
85            echo "これはDom\\Text (テキストノード) です。\n";
86            echo "テキストコンテンツ: '" . $previousSibling->textContent . "'\n";
87        } else {
88            echo "その他のノードタイプです。\n";
89        }
90    } else {
91        echo "ターゲットのDom\\Textノードには直前の兄弟ノードがありません。\n";
92        echo "これは、ターゲットノードが親要素の最初の子である場合に発生します。\n";
93    }
94}
95
96// 関数を実行してサンプルコードの動作を確認します。
97demonstrateDomTextPreviousSibling();
98

PHP 8で導入されたDom\Text::previousSiblingプロパティは、HTMLやXMLドキュメント内で特定のテキストノードの直前にある兄弟ノードを取得するために用いられます。このプロパティは引数を必要とせず、現在のDom\Textノードの直前にある兄弟ノードをDom\Nodeオブジェクトとして返します。もし直前の兄弟ノードが存在しない場合、例えば対象のテキストノードが親要素の最初の子である場合にはnullが戻り値となります。

サンプルコードでは、<div><span>Hello</span> World<p>PHP</p></div>というHTMLから、「 World」というテキストノードを対象としています。従来のDOMDocumentを使ってHTMLを解析し、目的のDOMTextノードを見つけ出します。PHP 8の新機能を利用するため、この従来のDOMTextノードをDom\Text::createFromNode()メソッドでDom\Textオブジェクトに変換します。変換後、$domTextNode->previousSiblingプロパティにアクセスすることで、直前の兄弟ノードである<span>Hello</span>要素をDom\Nodeオブジェクトとして取得し、そのノード名や値などの詳細情報を画面に表示しています。この機能は、HTML構造をプログラムで操作する際に、特定のノードから前後関係を効率的に探索するために非常に役立ちます。

PHP 8以降でDom\Text::previousSiblingプロパティを利用する際は、いくつかの点に注意が必要です。まず、このプロパティはPHP 8で導入された新しいDom名前空間のクラスに属します。従来のDOMDocumentでHTMLを読み込んだ際に生成されるDOMTextオブジェクトは、直接このプロパティを持ちません。サンプルコードのように、Dom\Text::createFromNode()メソッドを使って従来のDOMTextオブジェクトを新しいDom\Textオブジェクトに変換してから利用する必要があります。変換を忘れるとエラーになりますのでご注意ください。

また、previousSiblingプロパティは、直前の兄弟ノードが存在しない場合(例:対象ノードが親要素の最初の子である場合)にはnullを返します。そのため、取得した結果がnullでないかを必ず確認し、適切な処理を行うことが重要です。HTMLの空白や改行もテキストノードとして認識される場合があるため、意図しないテキストノードを取得していないか、デバッグでDOMツリーをよく確認することをおすすめします。

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

1<?php
2
3/**
4 * Dom\Text::previousSibling プロパティの使用例を示す関数。
5 *
6 * この関数は、HTML文字列から特定のテキストノードを見つけ、
7 * その直前の兄弟ノード (previousSibling) を取得して表示します。
8 */
9function getPreviousSiblingOfTextNode(): void
10{
11    // DOMDocument オブジェクトを作成
12    $dom = new DOMDocument();
13
14    // サンプルHTML文字列を読み込む
15    // <p>要素の後に直接テキストノードを配置し、previousSiblingの動作を確認する。
16    $htmlContent = <<<HTML
17<!DOCTYPE html>
18<html>
19<body>
20    <div>
21        <p>最初の要素ノードです。</p>
22        これはターゲットテキストです。
23        <span>次の要素ノードです。</span>
24    </div>
25</body>
26</html>
27HTML;
28    
29    // HTMLパース時のエラーを抑制(実運用ではエラーハンドリングを推奨)
30    libxml_use_internal_errors(true);
31    $dom->loadHTML($htmlContent);
32    libxml_use_internal_errors(false);
33
34    echo "--- 処理対象のHTMLコンテンツ ---\n";
35    echo $htmlContent;
36    echo "---------------------------------\n\n";
37
38    $targetTextNode = null;
39    $divElements = $dom->getElementsByTagName('div');
40
41    if ($divElements->length > 0) {
42        $div = $divElements[0]; // 最初のdiv要素を取得
43        foreach ($div->childNodes as $childNode) {
44            // テキストノードであり、かつ内容が空でないものを対象とする
45            if ($childNode instanceof DOMText && trim($childNode->nodeValue) !== '') {
46                // "これはターゲットテキストです。" という文字列を含むノードを探す
47                if (str_contains($childNode->nodeValue, 'これはターゲットテキストです。')) {
48                    $targetTextNode = $childNode;
49                    break;
50                }
51            }
52        }
53    }
54
55    if ($targetTextNode) {
56        echo "見つかったターゲットテキストノード: '" . trim($targetTextNode->nodeValue) . "'\n\n";
57
58        // Dom\Text::previousSibling プロパティにアクセス
59        // 直前の兄弟ノードが Dom\Node オブジェクトとして、または見つからなければ null で返される
60        $previousSibling = $targetTextNode->previousSibling;
61
62        echo "ターゲットテキストノードの直前の兄弟ノード (previousSibling):\n";
63
64        if ($previousSibling instanceof DOMNode) {
65            echo "  ノードタイプ: " . get_node_type_name($previousSibling->nodeType) . "\n";
66            echo "  ノード名: " . $previousSibling->nodeName . "\n";
67            // ノード値は長くなることがあるので、適度に切り詰めて表示
68            echo "  ノード値 (一部): '" . mb_strimwidth(trim($previousSibling->nodeValue), 0, 50, "...") . "'\n";
69            
70            // 要素ノードの場合、追加情報としてタグ名も表示
71            if ($previousSibling instanceof DOMElement) {
72                echo "  タグ名: " . $previousSibling->tagName . "\n";
73            }
74        } else {
75            echo "  直前の兄弟ノードは見つかりませんでした (null)。\n";
76        }
77    } else {
78        echo "指定されたテキストノードが見つかりませんでした。\n";
79    }
80}
81
82/**
83 * DOMノードタイプ番号を対応する文字列名に変換するヘルパー関数。
84 *
85 * @param int $node_type DOMノードタイプ番号
86 * @return string ノードタイプ名
87 */
88function get_node_type_name(int $node_type): string
89{
90    return match ($node_type) {
91        XML_ELEMENT_NODE        => 'ELEMENT_NODE',
92        XML_ATTRIBUTE_NODE      => 'ATTRIBUTE_NODE',
93        XML_TEXT_NODE           => 'TEXT_NODE',
94        XML_CDATA_SECTION_NODE  => 'CDATA_SECTION_NODE',
95        XML_ENTITY_REF_NODE     => 'ENTITY_REFERENCE_NODE',
96        XML_ENTITY_NODE         => 'ENTITY_NODE',
97        XML_PI_NODE             => 'PROCESSING_INSTRUCTION_NODE',
98        XML_COMMENT_NODE        => 'COMMENT_NODE',
99        XML_DOCUMENT_NODE       => 'DOCUMENT_NODE',
100        XML_DOCUMENT_TYPE_NODE  => 'DOCUMENT_TYPE_NODE',
101        XML_DOCUMENT_FRAG_NODE  => 'DOCUMENT_FRAGMENT_NODE',
102        XML_NOTATION_NODE       => 'NOTATION_NODE',
103        default                 => 'UNKNOWN_NODE_TYPE',
104    };
105}
106
107// 関数の実行
108getPreviousSiblingOfTextNode();
109
110?>

Dom\Text::previousSiblingプロパティは、PHPのDOM拡張機能において、HTMLやXML文書内の特定のテキストノードの直前にある兄弟ノードを取得するために使用されます。兄弟ノードとは、同じ親要素の下に並んでいるノードのことです。このプロパティには引数はなく、戻り値は、直前の兄弟ノードが存在すればそのノードを示すDom\Nodeオブジェクト、存在しない場合はnullとなります。

サンプルコードでは、まずPHPのDOMDocumentクラスを用いてHTMLコンテンツを読み込み、DOMツリーを構築しています。次に、文書中から「これはターゲットテキストです。」という文字列を含む特定のテキストノードを探し出します。そのテキストノードが見つかったら、$targetTextNode->previousSiblingのようにプロパティにアクセスすることで、直前の兄弟ノードを取得しています。取得した兄弟ノードが存在する場合(nullではない場合)、そのノードの種類や名前、値などの詳細情報を表示しています。この機能を使うことで、DOMツリー内でのノード間の相対的な位置関係を簡単に調べ、文書構造を操作する際に役立てることができます。

Dom\Text::previousSiblingプロパティは、現在のテキストノードの直前の兄弟ノードを取得します。直前の兄弟ノードが存在しない場合はnullを返すため、必ず取得した値がnullでないかを確認してから利用してください。HTMLを解析する際、改行やスペースなどもテキストノードとして扱われることがあります。そのため、意図しない空白だけのテキストノードが兄弟ノードとして返される可能性も考慮し、trim()などでノード値が空でないかをチェックすると良いでしょう。また、返されるノードは要素ノード、テキストノード、コメントノードなど多岐にわたりますので、instanceofで種類を判別し、それぞれに合った処理を記述することが重要です。DOMDocument::loadHTMLでHTMLを読み込む際には、パースエラーが発生することがありますので、実運用ではエラーハンドリングを適切に行うことを強くお勧めします。

関連コンテンツ

関連プログラミング言語