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

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

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

作成日: 更新日:

基本的な使い方

previousSiblingプロパティは、DOM (Document Object Model) ツリーにおいて、現在のノードの直前にある兄弟ノードを保持するプロパティです。このプロパティは、PHPのDOM拡張機能の一部であるDom\Notationクラスに属しています。Dom\Notationクラスのインスタンスは、XMLまたはHTMLドキュメントのDTD (Document Type Definition) 内で定義されるNOTATION宣言を表すノードです。

DOMツリーは、ドキュメントの構造を木のような階層で表現し、各要素、属性、テキストなどが「ノード」として扱われます。兄弟ノードとは、同じ親ノードを持つノード同士を指します。Dom\Notationオブジェクトに対してこのpreviousSiblingプロパティにアクセスすると、そのNOTATIONノードのすぐ前にある兄弟ノードが返されます。

もし現在のDom\Notationノードの直前に兄弟ノードが存在しない場合は、このプロパティはnullを返します。この機能により、DOMツリー内でノードを前方にたどって巡回したり、特定のノードを見つけ出したりすることが可能となります。XMLやHTMLドキュメントの構造をプログラムで操作する際に、ノード間の関係性を把握し、効率的に移動するために重要な役割を果たします。

構文(syntax)

1<?php
2
3$xmlString = <<<XML
4<?xml version="1.0"?>
5<!DOCTYPE root [
6  <!NOTATION type_a SYSTEM "uri:type_a">
7  <!NOTATION type_b SYSTEM "uri:type_b">
8]>
9<root/>
10XML;
11
12$dom = new DOMDocument();
13$dom->loadXML($xmlString);
14
15$docType = $dom->doctype;
16$notations = $docType->notations;
17
18$notation = $notations->item(1);
19
20$previousSiblingNode = $notation->previousSibling;
21
22?>

引数(parameters)

引数なし

引数はありません

戻り値(return)

Dom\Node|null

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

サンプルコード

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

1<?php
2
3/**
4 * Dom\Notation::previousSibling プロパティの使用例をデモンストレーションします。
5 *
6 * Dom\Notation は、XML DTD (Document Type Definition) 内で外部データ型を宣言するために使用されるノードです。
7 * previousSibling プロパティは、そのノードの直前の兄弟ノードを返します。
8 * これは、DTD 内でのノードの順序をたどる際に役立ちます。
9 *
10 * @return void
11 */
12function demonstrateDomNotationPreviousSibling(): void
13{
14    // DTD (Document Type Definition) を含むXML文字列を作成します。
15    // Dom\Notation は通常のXMLドキュメントの要素とは異なり、DTD内で定義されます。
16    // ここでは2つのNOTATIONを定義し、その後に要素定義を配置することで、
17    // 兄弟ノードの関係を明確にします。
18    $xmlString = <<<XML
19<?xml version="1.0" encoding="UTF-8"?>
20<!DOCTYPE root [
21  <!NOTATION gif PUBLIC "image/gif">
22  <!NOTATION jpeg SYSTEM "image/jpeg">
23  <!ELEMENT myelement EMPTY>
24]>
25<root/>
26XML;
27
28    // DOMDocument オブジェクトを作成し、XML文字列をロードします。
29    $dom = new DOMDocument();
30    // 外部エンティティのロードを防ぎ、セキュリティを向上させる設定
31    $dom->setSecurityParams(LIBXML_DOTTED_VERSION, true, true);
32    $dom->loadXML($xmlString);
33
34    echo "--- Dom\\Notation::previousSibling のデモンストレーション --- \n";
35
36    // ドキュメントタイプノード (Dom\DocumentType) を取得します。
37    // DTD の情報は通常、このノードからアクセスできます。
38    $doctype = $dom->doctype;
39
40    if (!$doctype) {
41        echo "エラー: ドキュメントタイプノードが見つかりませんでした。\n";
42        return;
43    }
44
45    // Dom\DocumentType から全ての NOTATION ノードのコレクションを取得します。
46    // notations プロパティは Dom\NamedNodeMap を返します。
47    $notations = $doctype->notations;
48
49    if ($notations->length === 0) {
50        echo "DTD 内に NOTATION 定義が見つかりませんでした。\n";
51        return;
52    }
53
54    echo "DTD 内の NOTATION ノードを処理します。\n";
55
56    // 「jpeg」という名前の NOTATION ノードを探し、その前の兄弟ノードを確認します。
57    // XML定義順から、'jpeg' の前の兄弟は 'gif' であると期待されます。
58    /** @var Dom\Notation|null $jpegNotation */
59    $jpegNotation = null;
60    foreach ($notations as $notation) {
61        // Dom\NamedNodeMap の要素は Dom\Node であるため、Dom\Notation にキャスト可能かチェックします。
62        if ($notation instanceof Dom\Notation && $notation->nodeName === 'jpeg') {
63            $jpegNotation = $notation;
64            break;
65        }
66    }
67
68    if ($jpegNotation) {
69        echo "\n--- 'jpeg' NOTATION の情報 --- \n";
70        echo "ノード名: " . $jpegNotation->nodeName . "\n";
71        echo "パブリックID: " . $jpegNotation->publicId . "\n";
72        echo "システムID: " . $jpegNotation->systemId . "\n";
73
74        // previousSibling プロパティを使って直前の兄弟ノードを取得します。
75        // このプロパティは Dom\Node または null を返します。
76        $previousSibling = $jpegNotation->previousSibling;
77
78        echo "\n--- 'jpeg' NOTATION の previousSibling の情報 --- \n";
79        if ($previousSibling) {
80            echo "前の兄弟ノードが見つかりました。\n";
81            echo "ノード名: " . $previousSibling->nodeName . "\n";
82            echo "ノードタイプ: " . $previousSibling->nodeType . " (";
83            // ノードタイプを可読な文字列で表示し、初心者の理解を助けます。
84            echo match ($previousSibling->nodeType) {
85                XML_ELEMENT_NODE => 'XML_ELEMENT_NODE',
86                XML_ATTRIBUTE_NODE => 'XML_ATTRIBUTE_NODE',
87                XML_TEXT_NODE => 'XML_TEXT_NODE',
88                XML_CDATA_SECTION_NODE => 'XML_CDATA_SECTION_NODE',
89                XML_ENTITY_REF_NODE => 'XML_ENTITY_REF_NODE',
90                XML_ENTITY_NODE => 'XML_ENTITY_NODE',
91                XML_PI_NODE => 'XML_PI_NODE',
92                XML_COMMENT_NODE => 'XML_COMMENT_NODE',
93                XML_DOCUMENT_NODE => 'XML_DOCUMENT_NODE',
94                XML_DOCUMENT_TYPE_NODE => 'XML_DOCUMENT_TYPE_NODE',
95                XML_DOCUMENT_FRAG_NODE => 'XML_DOCUMENT_FRAG_NODE',
96                XML_NOTATION_NODE => 'XML_NOTATION_NODE',
97                // DTD関連のノードタイプも存在しますが、ここでは代表的なものを列挙します。
98                default => 'UNKNOWN_NODE_TYPE',
99            };
100            echo ")\n";
101
102            // 返されたノードが Dom\Notation のインスタンスであれば、その詳細も表示します。
103            if ($previousSibling instanceof Dom\Notation) {
104                echo "前の兄弟ノードは別の Dom\\Notation です。\n";
105                echo "前の兄弟ノード名: " . $previousSibling->nodeName . "\n";
106                echo "前の兄弟ノードのパブリックID: " . $previousSibling->publicId . "\n";
107            }
108        } else {
109            echo "前の兄弟ノードは見つかりませんでした(null)。\n";
110        }
111    } else {
112        echo "エラー: 'jpeg' という名前の Dom\\Notation ノードが見つかりませんでした。\n";
113    }
114
115    echo "\n--- 最初の NOTATION ('gif') の previousSibling の情報 --- \n";
116    // 最初の NOTATION である「gif」の previousSibling は null になるはずです。
117    /** @var Dom\Notation|null $gifNotation */
118    $gifNotation = null;
119    foreach ($notations as $notation) {
120        if ($notation instanceof Dom\Notation && $notation->nodeName === 'gif') {
121            $gifNotation = $notation;
122            break;
123        }
124    }
125
126    if ($gifNotation) {
127        $previousSiblingOfGif = $gifNotation->previousSibling;
128        if ($previousSiblingOfGif) {
129            echo "'gif' NOTATION の前の兄弟ノードが見つかりました。\n";
130            echo "ノード名: " . $previousSiblingOfGif->nodeName . "\n";
131        } else {
132            echo "'gif' NOTATION には前の兄弟ノードはありません(null)。これは期待される結果です。\n";
133        }
134    } else {
135        echo "エラー: 'gif' という名前の Dom\\Notation ノードが見つかりませんでした。\n";
136    }
137}
138
139// デモンストレーション関数を実行します。
140demonstrateDomNotationPreviousSibling();

PHP 8のDom\Notation::previousSiblingプロパティは、XML DTD(Document Type Definition)内で定義される表記宣言(Notation)ノードの直前の兄弟ノードを取得するために使われるプロパティです。Dom\Notationは、外部データの形式や処理方法を宣言する際に使われる、DTD内の特別なノードです。

このサンプルコードでは、gifjpegという2つのNOTATIONを含むXML DTDを定義したXML文字列をDOMDocumentにロードしています。そして、ドキュメントのDTD情報からDom\Notationノードのコレクションを取り出します。コードは特にjpegという名前のNOTATIONノードを探し、そのpreviousSiblingプロパティを利用して直前の兄弟ノードが何であるかを確認しています。

previousSiblingプロパティには引数はなく、戻り値として直前の兄弟ノードが見つかればDom\Nodeオブジェクトを、見つからない場合はnullを返します。サンプルでは、jpegの前の兄弟ノードとしてgifDom\Notationノードが取得されること、またDTD内で最初のNOTATIONであるgifには前の兄弟ノードが存在しないためnullが返されることを示しています。このプロパティは、XMLツリー構造におけるノードの順序関係をプログラムで確認する際に有用です。

このサンプルコードは、DTD内で定義される特殊なノードであるDom\NotationpreviousSiblingプロパティの利用方法を示しています。このプロパティは、直前の兄弟ノードをDom\Nodeオブジェクトとして返しますが、兄弟ノードが存在しない場合はnullを返しますので、必ず返り値がnullでないかを確認してください。また、返される兄弟ノードは常にDom\Notation型であるとは限りません。DTD内には要素型宣言やエンティティ宣言など、異なる種類のノードも存在するため、返り値のinstanceofnodeTypeプロパティでノードの型を適切に判断し、処理を分岐させることが重要です。Dom\Notationは一般的なXML要素とは異なり、XMLのDTD内で定義される特殊なノードである点を理解しておくと、より安全で正確なDOM操作に役立ちます。

Dom\NotationのpreviousSiblingを取得する

1<?php
2
3/**
4 * Dom\Notation クラスの previousSibling プロパティの動作を示すサンプルコードです。
5 *
6 * Dom\Notation は XML の DTD (Document Type Definition) 内で外部の非XMLデータを
7 * 参照するために使用される「表記宣言」を表します。
8 * Dom\Node を継承しているため previousSibling プロパティを持ちますが、
9 * DTD 内の表記ノードは一般的な DOM ツリーの要素とは異なり、通常は兄弟ノードを持たないため、
10 * このプロパティにアクセスすると null が返されることが多いです。
11 */
12function demonstrateNotationPreviousSibling(): void
13{
14    // XML ドキュメントと DTD (Document Type Definition) を定義します。
15    // ここでは、2つの NOTATION (image_gif と image_jpeg) を定義しています。
16    $xmlString = <<<XML
17<!DOCTYPE document [
18<!NOTATION image_gif PUBLIC "-//MYORG//NONSGML GIF Image//EN">
19<!NOTATION image_jpeg PUBLIC "-//MYORG//NONSGML JPEG Image//EN">
20<!ELEMENT document EMPTY>
21]>
22<document/>
23XML;
24
25    $dom = new DOMDocument();
26    // 外部エンティティのロードを有効にします。
27    // DTD の NOTATION を適切に解析するために、この設定が役立つ場合があります。
28    $dom->resolveExternals = true;
29    // XML 文字列を DOM オブジェクトにロードします。
30    $dom->loadXML($xmlString);
31
32    // ドキュメントの DTD (Document Type Definition) オブジェクトを取得します。
33    $docType = $dom->doctype;
34
35    // DTD とその中に NOTATION が定義されているかを確認します。
36    if ($docType && $docType->notations->length > 0) {
37        echo "DTD に NOTATION が見つかりました。\n\n";
38
39        // DTD の notations (表記宣言) のリストから最初の Dom\Notation ノードを取得します。
40        // notations は Dom\NamedNodeMap のインスタンスであり、要素は Dom\Notation オブジェクトです。
41        $firstNotation = $docType->notations->item(0);
42
43        // 取得したノードが Dom\Notation のインスタンスであることを確認します。
44        if ($firstNotation instanceof Dom\Notation) {
45            echo "最初の NOTATION ノード: {$firstNotation->nodeName}\n";
46
47            // previousSibling プロパティにアクセスし、前の兄弟ノードを取得します。
48            // DTD の notations 内のノードは、DOM ツリーのような親-子-兄弟の関係を直接持たないため、
49            // 通常は null が返されます。
50            $previousSibling = $firstNotation->previousSibling;
51
52            if ($previousSibling === null) {
53                echo "-> previousSibling は null です (前の兄弟ノードが存在しません)。\n";
54            } else {
55                echo "-> previousSibling: " . $previousSibling->nodeName . " (ノードタイプ: " . $previousSibling->nodeType . ")\n";
56            }
57        } else {
58            echo "最初の表記ノードは Dom\\Notation のインスタンスではありませんでした。\n";
59        }
60
61        // 2番目の Dom\Notation ノードが存在する場合も同様に確認します。
62        // これも同様に null を返すことが期待されます。
63        if ($docType->notations->length > 1) {
64            echo "\n";
65            $secondNotation = $docType->notations->item(1);
66            if ($secondNotation instanceof Dom\Notation) {
67                echo "2番目の NOTATION ノード: {$secondNotation->nodeName}\n";
68                $previousSiblingOfSecond = $secondNotation->previousSibling;
69                if ($previousSiblingOfSecond === null) {
70                    echo "-> previousSibling は null です (前の兄弟ノードが存在しません)。\n";
71                } else {
72                    echo "-> previousSibling: " . $previousSiblingOfSecond->nodeName . " (ノードタイプ: " . $previousSiblingOfSecond->nodeType . ")\n";
73                }
74            } else {
75                echo "2番目の表記ノードは Dom\\Notation のインスタンスではありませんでした。\n";
76            }
77        }
78    } else {
79        echo "DTD が見つからないか、NOTATION が定義されていません。\n";
80    }
81}
82
83// 上記で定義した関数を実行します。
84demonstrateNotationPreviousSibling();

PHP 8のDom\Notationクラスは、XMLのDTD(Document Type Definition)内で、外部の非XMLデータを参照するために使われる「表記宣言」を表します。previousSiblingプロパティは、この表記ノードの「前の兄弟ノード」を取得するために使用されます。一般的なDOMツリーの要素は兄弟ノードを持つことがありますが、DTD内の表記ノードは通常、DOMツリーの他のノードとは異なる構造に存在するため、兄弟ノードを持たないことがほとんどです。

そのため、Dom\NotationオブジェクトからpreviousSiblingプロパティにアクセスしても、ほとんどの場合nullが返されます。このプロパティは引数を取らず、戻り値として前の兄弟ノードがDom\Nodeオブジェクトとして存在すればそのノードを、存在しなければnullを返します。

サンプルコードでは、XMLのDTD内に複数のNOTATIONを定義し、それらをDOMDocumentでロードしています。$dom->doctype->notationsを通じてDom\Notationオブジェクトを取得し、それぞれのpreviousSiblingプロパティにアクセスしています。実行結果は、想定通りnullが返されることを示しており、Dom\Notationの特殊な振る舞いを理解するのに役立ちます。previousSiblingは、ノード間の順序関係を確認したい場合に利用されるプロパティですが、Dom\Notationにおいては常にnullが返される可能性が高いことに注意が必要です。

このサンプルコードの注意点は、Dom\NotationクラスがXMLのDTD(Document Type Definition)内で定義される特殊なノードであり、一般的なDOMツリーの要素とは異なる点です。そのため、Dom\Nodeを継承していますが、previousSiblingプロパティにアクセスしても、通常は兄弟ノードが存在しないためnullが返されることがほとんどです。プロパティの戻り値がDom\Nodeまたはnullであるため、実際にノードが返されたか、nullであったかを常に確認する条件分岐を記述し、安全にコードを扱ってください。また、DOMDocument::resolveExternalstrueに設定することで、DTDの解析がより正確に行われる場合があります。

関連コンテンツ

関連IT用語

関連プログラミング言語