【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内の特別なノードです。
このサンプルコードでは、gifとjpegという2つのNOTATIONを含むXML DTDを定義したXML文字列をDOMDocumentにロードしています。そして、ドキュメントのDTD情報からDom\Notationノードのコレクションを取り出します。コードは特にjpegという名前のNOTATIONノードを探し、そのpreviousSiblingプロパティを利用して直前の兄弟ノードが何であるかを確認しています。
previousSiblingプロパティには引数はなく、戻り値として直前の兄弟ノードが見つかればDom\Nodeオブジェクトを、見つからない場合はnullを返します。サンプルでは、jpegの前の兄弟ノードとしてgifのDom\Notationノードが取得されること、またDTD内で最初のNOTATIONであるgifには前の兄弟ノードが存在しないためnullが返されることを示しています。このプロパティは、XMLツリー構造におけるノードの順序関係をプログラムで確認する際に有用です。
このサンプルコードは、DTD内で定義される特殊なノードであるDom\NotationのpreviousSiblingプロパティの利用方法を示しています。このプロパティは、直前の兄弟ノードをDom\Nodeオブジェクトとして返しますが、兄弟ノードが存在しない場合はnullを返しますので、必ず返り値がnullでないかを確認してください。また、返される兄弟ノードは常にDom\Notation型であるとは限りません。DTD内には要素型宣言やエンティティ宣言など、異なる種類のノードも存在するため、返り値のinstanceofやnodeTypeプロパティでノードの型を適切に判断し、処理を分岐させることが重要です。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::resolveExternalsをtrueに設定することで、DTDの解析がより正確に行われる場合があります。