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

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

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

作成日: 更新日:

基本的な使い方

previousSiblingプロパティは、Dom\DocumentTypeクラスに属し、現在のDOCTYPEノードの直前の兄弟ノードを保持するプロパティです。

Dom\DocumentTypeクラスは、HTMLやXMLドキュメントのDOCTYPE宣言、つまりドキュメントの型情報を定義する部分(例えば「<!DOCTYPE html>」のような記述)を表すノードです。このpreviousSiblingプロパティは、ドキュメントの構造を表すDOMツリーにおいて、現在のノードと親を共有し、現在のノードの直前に位置する別のノード(兄弟ノード)への参照を提供します。兄弟ノードとは、同じ親ノードを持つ、並んで位置するノードのことです。

Dom\DocumentTypeノードは、通常ドキュメントの最初の子要素として配置されることが多いため、このプロパティの値はnullになるケースが多いです。しかし、例えばXMLドキュメントでDOCTYPE宣言の前にXML宣言(<?xml version="1.0"?>のような処理命令)やコメントノードなどが存在する場合、それらのDom\NodeオブジェクトがpreviousSiblingとして返されることがあります。直前の兄弟ノードが存在しない場合は、このプロパティはnullを返します。このプロパティは、DOMツリーを探索し、隣接するノードの情報を取得する際に利用されます。

構文(syntax)

1<?php
2
3// DOMDocumentオブジェクトを作成し、HTMLドキュメントを読み込みます
4// この例では、<!DOCTYPE html> の前に兄弟ノードが存在しないシンプルなHTMLを使用します
5$dom = new DOMDocument();
6$dom->loadHTML('<!DOCTYPE html><html><head></head><body></body></html>');
7
8// ドキュメントからDocumentTypeノードを取得します
9// これは通常、<!DOCTYPE html> などの宣言を表すノードです
10$documentType = $dom->doctype;
11
12// DocumentTypeノードの直前の兄弟ノードを取得します
13// 直前の兄弟ノードが存在しない場合、nullが返されます
14$previousSiblingNode = $documentType->previousSibling;
15
16// 取得したノード(またはnull)を出力して確認します
17var_dump($previousSiblingNode);
18
19?>

引数(parameters)

引数なし

引数はありません

戻り値(return)

Dom\Node|null

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

サンプルコード

Dom\DocumentTypepreviousSibling を取得する

1<?php
2
3/**
4 * Dom\DocumentType の previousSibling プロパティの使用例を示します。
5 *
6 * この関数は、DOCTYPE宣言の前にコメントノードが存在するXMLドキュメントを作成し、
7 * その Dom\DocumentType ノードの直前の兄弟ノード (previousSibling) を取得します。
8 *
9 * Dom\DocumentType::previousSibling は、現在のノードの直前の兄弟ノードを Dom\Node オブジェクトとして返します。
10 * 直前の兄弟ノードが存在しない場合は null を返します。
11 * これは、システムエンジニアを目指す上でDOM操作の基本的な概念を理解するのに役立ちます。
12 *
13 * @return void
14 */
15function demonstrateDocumentTypePreviousSibling(): void
16{
17    // 1. XMLドキュメントを作成
18    // DOCTYPE宣言の前にコメントノードを配置し、previousSiblingがnullでないケースを例示します。
19    // これにより、previousSiblingが Dom\Node を返す具体的な例を見ることができます。
20    $xmlString = <<<XML
21<?xml version="1.0" encoding="UTF-8"?>
22<!-- This is a comment before the DOCTYPE declaration -->
23<!DOCTYPE greeting [
24  <!ELEMENT greeting (#PCDATA)>
25]>
26<greeting>Hello, world!</greeting>
27XML;
28
29    $dom = new Dom\Document();
30    // XMLをロードします。エラーが発生した場合、PHP 8のDom\DocumentはDom\Exceptionをスローします。
31    // このサンプルでは正しいXMLを使用することを前提とします。
32    $dom->loadXML($xmlString);
33
34    echo "--- パースされたドキュメントのXML --- \n";
35    echo $dom->saveXML() . "\n";
36    echo "----------------------------------- \n\n";
37
38    // 2. Dom\DocumentType ノードを取得
39    // Dom\DocumentType オブジェクトは、Dom\Document の 'doctype' プロパティから直接取得できます。
40    $documentType = $dom->doctype;
41
42    if ($documentType instanceof Dom\DocumentType) {
43        echo "Dom\DocumentType ノードが見つかりました。\n";
44        echo "ノード名: " . $documentType->nodeName . "\n"; // 例: "greeting" (DOCTYPEのルート要素名)
45        echo "パブリックID: " . ($documentType->publicId ?: '(なし)') . "\n";
46        echo "システムID: " . ($documentType->systemId ?: '(なし)') . "\n";
47        echo "内部サブセット: \n" . ($documentType->internalSubset ?: '(なし)') . "\n\n";
48
49        // 3. previousSibling プロパティを使用して直前の兄弟ノードを取得
50        // このプロパティは、現在のノードの直前にある兄弟ノードを返します。
51        $previousSibling = $documentType->previousSibling;
52
53        echo "--- previousSibling (直前の兄弟ノード) の確認 --- \n";
54        if ($previousSibling instanceof Dom\Node) {
55            echo "直前の兄弟ノードが見つかりました。\n";
56            echo "ノードタイプ: ";
57            // ノードタイプは整数値で、Dom\Node クラスの定数で意味が定義されています。
58            switch ($previousSibling->nodeType) {
59                case Dom\Node::ELEMENT_NODE:
60                    echo "要素ノード (ELEMENT_NODE)\n";
61                    break;
62                case Dom\Node::ATTRIBUTE_NODE:
63                    echo "属性ノード (ATTRIBUTE_NODE)\n"; // 兄弟ノードとしては稀
64                    break;
65                case Dom\Node::TEXT_NODE:
66                    echo "テキストノード (TEXT_NODE)\n";
67                    break;
68                case Dom\Node::CDATA_SECTION_NODE:
69                    echo "CDATAセクションノード (CDATA_SECTION_NODE)\n";
70                    break;
71                case Dom\Node::ENTITY_REFERENCE_NODE:
72                    echo "実体参照ノード (ENTITY_REFERENCE_NODE)\n";
73                    break;
74                case Dom\Node::ENTITY_NODE:
75                    echo "実体ノード (ENTITY_NODE)\n";
76                    break;
77                case Dom\Node::PROCESSING_INSTRUCTION_NODE:
78                    echo "処理命令ノード (PROCESSING_INSTRUCTION_NODE)\n";
79                    break;
80                case Dom\Node::COMMENT_NODE:
81                    echo "コメントノード (COMMENT_NODE)\n";
82                    break;
83                case Dom\Node::DOCUMENT_NODE:
84                    echo "ドキュメントノード (DOCUMENT_NODE)\n"; // 兄弟ノードとしては稀
85                    break;
86                case Dom\Node::DOCUMENT_TYPE_NODE:
87                    echo "ドキュメントタイプノード (DOCUMENT_TYPE_NODE)\n";
88                    break;
89                case Dom\Node::DOCUMENT_FRAGMENT_NODE:
90                    echo "ドキュメントフラグメントノード (DOCUMENT_FRAGMENT_NODE)\n";
91                    break;
92                case Dom\Node::NOTATION_NODE:
93                    echo "記法ノード (NOTATION_NODE)\n";
94                    break;
95                default:
96                    echo "不明なノードタイプ\n";
97                    break;
98            }
99            echo "ノード名: " . $previousSibling->nodeName . "\n";   // コメントの場合 "#comment"
100            echo "ノード値: " . $previousSibling->nodeValue . "\n"; // コメントの場合 コメントの内容
101        } else {
102            echo "直前の兄弟ノードは存在しません (null)。\n";
103            echo "これは、Dom\DocumentType がドキュメントの最初のノードである場合によく発生します。\n";
104        }
105        echo "------------------------------------------------ \n\n";
106
107        // 参考: 一般的なHTMLドキュメントでの previousSibling (null になる例)
108        // 多くのHTMLドキュメントでは、DOCTYPE宣言が最初のノードとなるため、previousSibling は null になります。
109        echo "--- 参考: 一般的なHTMLでの previousSibling (null になるケース) --- \n";
110        $htmlDom = new Dom\Document();
111        // HTML文字列をロード
112        $htmlDom->loadHTML('<!DOCTYPE html><html><head><title>Test</title></head><body><h1>Hello</h1></body></html>');
113        $htmlDocumentType = $htmlDom->doctype;
114
115        if ($htmlDocumentType instanceof Dom\DocumentType) {
116            $htmlPreviousSibling = $htmlDocumentType->previousSibling;
117            if ($htmlPreviousSibling === null) {
118                echo "HTMLの `<!DOCTYPE html>` の previousSibling は `null` です。\n";
119                echo "(これは、HTMLのDOCTYPEが通常ドキュメントの最初のノードであるためです。)\n";
120            } else {
121                echo "HTMLの `<!DOCTYPE html>` の previousSibling は存在します。\n";
122                // このケースは通常発生しないため、詳細な表示は省略します。
123            }
124        } else {
125            echo "HTMLドキュメントに Dom\DocumentType ノードが見つかりませんでした。\n";
126        }
127        echo "---------------------------------------------------------------- \n";
128
129    } else {
130        echo "Dom\DocumentType ノードが見つかりませんでした。\n";
131        echo "提供されたXML/HTMLにDOCTYPE宣言が存在しないか、パースに失敗した可能性があります。\n";
132    }
133}
134
135// サンプル関数の実行
136demonstrateDocumentTypePreviousSibling();

PHP 8 の Dom\DocumentType::previousSibling プロパティは、ドキュメントオブジェクトモデル (DOM) において、特定のノードの直前の兄弟ノードを取得するために使用されます。このプロパティは引数を取らず、現在の Dom\DocumentType ノードの直前に位置する兄弟ノードを Dom\Node オブジェクトとして返します。もし直前の兄弟ノードが存在しない場合は null を返します。

サンプルコードでは、まず <!DOCTYPE> 宣言の前にコメントノードを含むXMLドキュメントを作成し、これをパースしています。そのドキュメントから Dom\DocumentType ノードを取得し、previousSibling プロパティにアクセスすると、直前のコメントノードが Dom\Node オブジェクトとして取得される様子が確認できます。これにより、ノードのタイプや値といった詳細情報もプログラムで把握できることが示されています。

また、一般的なHTMLドキュメントのように <!DOCTYPE html> がドキュメントの最初のノードである場合には、previousSiblingnull を返すという、異なるケースも併せて示されています。このように、ノードが持つ兄弟関係を理解し、適切にアクセスする方法を学ぶことは、XMLやHTMLなどの構造化されたデータを扱うシステム開発において基本的なスキルとなります。

previousSiblingプロパティは、対象ノードの直前にある兄弟ノードを返しますが、存在しない場合はnullを返します。そのため、必ずnullチェックを行うことが重要です。特に、<!DOCTYPE>宣言がドキュメントの最初の実質的なノードである場合、このプロパティはnullを返します。サンプルコードのように、<!DOCTYPE>の前にコメントノードや処理命令などが存在する場合にのみ、Dom\Nodeオブジェクトが返されます。返されたノードがどの種類かを確認するには、nodeTypeプロパティを利用し、適切な処理を実装してください。また、Dom\Document::loadXML()loadHTML()によるXMLパース時には例外が発生する可能性も考慮し、エラーハンドリングを検討することが安全なコード利用に繋がります。

Dom\DocumentType::previousSibling を取得する

1<?php
2
3/**
4 * Dom\DocumentType::previousSibling プロパティの動作をデモンストレーションします。
5 *
6 * このプロパティは、現在のノードの直前にある兄弟ノードを返します。
7 * 直前の兄弟ノードが存在しない場合は null を返します。
8 * DocumentType は通常、ドキュメントの最初の子ノードであるため、
9 * その previousSibling はほとんどの場合 null になります。
10 * しかし、DOM操作によって他のノードがその前に挿入される可能性もあります。
11 */
12function demonstrateDocumentTypePreviousSibling(): void
13{
14    // 新しいDOMドキュメントを作成します。
15    $dom = new Dom\Document();
16
17    // <!DOCTYPE html> に相当する Dom\DocumentType ノードを作成します。
18    $doctype = $dom->implementation->createDocumentType('html', '', '');
19
20    // ドキュメントに Dom\DocumentType ノードを最初の子として追加します。
21    $dom->appendChild($doctype);
22
23    echo "--- ケース 1: Dom\DocumentType が最初の子ノードの場合 ---\n";
24    // この時点で Dom\DocumentType はドキュメントの最初の子ノードなので、
25    // 直前の兄弟ノードは存在しません。
26    $previousSiblingCase1 = $doctype->previousSibling;
27
28    if ($previousSiblingCase1 === null) {
29        echo "結果: Dom\\DocumentType->previousSibling は null です。(期待通り)\n";
30    } else {
31        echo "結果: Dom\\DocumentType->previousSibling は " . get_class($previousSiblingCase1) . " 型のノードです。\n";
32    }
33    echo "\n";
34
35    // Dom\DocumentType ノードの前にコメントノードを挿入します。
36    // これは通常のHTML/XML構造では稀ですが、DOM操作によって可能です。
37    $commentNode = $dom->createComment(' このコメントはDOCTYPE宣言の前にあります ');
38    $dom->insertBefore($commentNode, $doctype); // $doctype の前に $commentNode を挿入
39
40    echo "--- ケース 2: Dom\DocumentType の前に別のノードが挿入された場合 ---\n";
41    // コメントが挿入された後、Dom\DocumentType の直前の兄弟ノードは
42    // 先ほど挿入したコメントノードになります。
43    $previousSiblingCase2 = $doctype->previousSibling;
44
45    if ($previousSiblingCase2 instanceof Dom\Node) {
46        echo "結果: Dom\\DocumentType->previousSibling は " . get_class($previousSiblingCase2) . " 型のノードです。\n";
47        echo "取得されたノードの種類: " . $previousSiblingCase2->nodeName . "\n";
48        echo "取得されたノードの値: '" . $previousSiblingCase2->nodeValue . "'\n";
49    } else {
50        echo "結果: Dom\\DocumentType->previousSibling は null です。(この場合は予期せぬ結果)\n";
51    }
52    echo "\n";
53
54    echo "--- ドキュメントの最終的なノード構造(部分表示)---\n";
55    foreach ($dom->childNodes as $node) {
56        if ($node === $doctype) {
57            echo "- DocumentType (現在のターゲットノード)\n";
58        } elseif ($node === $commentNode) {
59            echo "- Comment (DocumentType の直前の兄弟ノード)\n";
60        } else {
61            echo "- その他のノード: " . $node->nodeName . "\n";
62        }
63    }
64}
65
66// デモンストレーション関数を実行します。
67demonstrateDocumentTypePreviousSibling();

Dom\DocumentType::previousSiblingプロパティは、現在のDom\DocumentTypeノードの直前に位置する兄弟ノードを取得します。このプロパティは引数を取りません。直前の兄弟ノードが存在すればDom\Nodeオブジェクトを、存在しなければnullを返します。

Dom\DocumentTypeは通常、HTMLやXMLドキュメントの構造上、ドキュメントの最初の子ノードとして配置されるため、そのpreviousSiblingはほとんどの場合nullとなります。

サンプルコードでは、まずDom\DocumentTypeノードをドキュメントの最初の子として追加し、この状態でのpreviousSiblingnullを返すことを確認しています。次に、DOM操作によってDom\DocumentTypeノードの前にコメントノードを意図的に挿入します。この操作後、再度previousSiblingを参照すると、直前に挿入されたコメントノード(Dom\Commentオブジェクト)が返されることを示しています。このデモンストレーションにより、previousSiblingプロパティがDOMツリーにおけるノードの相対的な位置関係を正確に反映する動作が明確に理解できます。

Dom\DocumentType::previousSiblingプロパティは、現在のノードの直前にある兄弟ノードを返します。ただし、直前の兄弟ノードが存在しない場合はnullを返す点に注意が必要です。Dom\DocumentTypeは通常、ドキュメントの最初の子ノードとして扱われるため、このプロパティはほとんどの場合nullを返します。しかし、DOM操作によって別のノードがDom\DocumentTypeの前に挿入された場合は、その挿入されたノードが返されます。そのため、戻り値がDom\Nodeオブジェクトであるかnullであるかを必ず確認し、それに応じた処理を行う必要があります。これにより、意図しないエラーを防ぎ、プログラムの安定性を保つことができます。このnullチェックは、DOMノードの兄弟関係を扱う際の基本的な習慣として身につけることが重要です。

関連コンテンツ

関連IT用語

関連プログラミング言語