【PHP8.x】DOMEntityReference::nextSiblingプロパティの使い方
nextSiblingプロパティの使い方について、初心者にもわかりやすく解説します。
基本的な使い方
『nextSiblingプロパティは、現在のDOMEntityReferenceノードの直後に存在する兄弟ノードを保持するプロパティです。DOMツリー構造において、同じ親ノードを持つノード群の中で、現在のノードのすぐ次に位置するノードが「次の兄弟ノード」となります。このプロパティを利用することで、ドキュメント内のノードを順番に処理する、いわゆる兄弟間の走査が可能になります。
もし現在のノードが、その親ノードにおける最後の子ノードである場合、直後に兄弟ノードは存在しないため、このプロパティは null を返します。この null チェックにより、兄弟ノードの終端を判定できます。取得されるノードは、要素ノード(タグ)だけでなく、テキストノード、コメントノード、あるいは改行やインデントによる空白文字のみを含むテキストノードなど、あらゆる種類のノードである可能性がある点に注意が必要です。
このプロパティは読み取り専用であり、直接値を代入してDOMツリーの構造を書き換えることはできません。ノードの挿入や移動といった操作には、DOMNode::insertBefore() などの専用メソッドを使用する必要があります。
構文(syntax)
1<?php 2 3$xml = <<<XML 4<!DOCTYPE root [ 5 <!ENTITY my_entity "some text"> 6]> 7<root><item1/>&my_entity;<item2/></root> 8XML; 9 10$doc = new DOMDocument(); 11 12// Set to false to prevent entity substitution and create DOMEntityReference nodes 13$doc->substituteEntities = false; 14 15$doc->loadXML($xml); 16 17// Get the root element's child nodes 18$childNodes = $doc->documentElement->childNodes; 19 20// Find the DOMEntityReference node (&my_entity;) 21$entityRefNode = null; 22foreach ($childNodes as $node) { 23 if ($node->nodeType === XML_ENTITY_REF_NODE) { 24 $entityRefNode = $node; 25 break; 26 } 27} 28 29// Access the node immediately following the entity reference node 30// The property returns a ?DOMNode (DOMNode or null) 31$siblingNode = $entityRefNode->nextSibling; 32 33if ($siblingNode) { 34 // Outputs the node name of the next sibling, which is "item2" 35 echo $siblingNode->nodeName; 36} 37 38?>
引数(parameters)
引数なし
引数はありません
戻り値(return)
DOMNode|null
このプロパティは、現在のDOMエンティティ参照ノードの次に位置する兄弟ノード、または兄弟ノードが存在しない場合はnullを返します。
サンプルコード
DOMEntityReferenceのnextSiblingを取得する
1<?php 2 3/** 4 * DOMEntityReferenceのnextSiblingプロパティの使用例を示します。 5 * 6 * この関数は、DTDでエンティティが定義されたXML文字列を解析します。 7 * そして、特定のエンティティ参照ノード(&company;)を見つけ、 8 * その直後にある兄弟ノード(この場合はテキストノード)の内容を取得して出力します。 9 */ 10function showNextSiblingOfEntityReference(): void 11{ 12 // DTDでエンティティ'&company;'を定義したXML文字列 13 $xmlString = <<<XML 14<?xml version="1.0" encoding="UTF-8"?> 15<!DOCTYPE document [ 16 <!ENTITY company "Example Corp."> 17]> 18<document> 19 <copyright>Copyright &company; 2023. All rights reserved.</copyright> 20</document> 21XML; 22 23 // DOMDocumentオブジェクトをインスタンス化 24 $dom = new DOMDocument(); 25 26 // XML文字列を読み込みます。 27 // デフォルトのオプションでは、エンティティ参照はDOMEntityReferenceノードとして扱われます。 28 $dom->loadXML($xmlString); 29 30 // <copyright>要素を取得 31 $copyrightElement = $dom->getElementsByTagName('copyright')->item(0); 32 if ($copyrightElement === null) { 33 echo "要素が見つかりませんでした。" . PHP_EOL; 34 return; 35 } 36 37 // <copyright>要素の子ノードをループしてDOMEntityReferenceを探す 38 foreach ($copyrightElement->childNodes as $childNode) { 39 if ($childNode instanceof DOMEntityReference) { 40 echo "エンティティ参照ノードが見つかりました: &" . $childNode->nodeName . ";" . PHP_EOL; 41 42 // nextSiblingプロパティで次の兄弟ノードを取得 43 $nextSiblingNode = $childNode->nextSibling; 44 45 // 次の兄弟ノードが存在するか確認 46 if ($nextSiblingNode !== null) { 47 // 次のノードはテキストノード " 2023. All rights reserved." 48 echo "次の兄弟ノードの型: " . get_class($nextSiblingNode) . PHP_EOL; 49 echo "次の兄弟ノードの値: '" . trim($nextSiblingNode->nodeValue) . "'" . PHP_EOL; 50 } else { 51 echo "次の兄弟ノードはありません。" . PHP_EOL; 52 } 53 // 目的のノードを見つけたらループを終了 54 break; 55 } 56 } 57} 58 59// 関数を実行 60showNextSiblingOfEntityReference(); 61 62?>
このサンプルコードは、PHPのDOMEntityReferenceクラスが持つnextSiblingプロパティの使用方法を示しています。nextSiblingは、XML文書内のあるエンティティ参照ノードを基準として、その直後にある同じ階層のノード(兄弟ノード)を取得するためのプロパティです。引数は必要ありません。戻り値は、次の兄弟ノードが存在すればそのノードを表すDOMNodeオブジェクト、存在しなければnullとなります。
コードでは、まずDTD(文書型定義)でエンティティ&company;を定義したXML文字列をDOMDocumentオブジェクトとして読み込みます。次に、<copyright>要素の子ノードを一つずつ調べ、目的のエンティティ参照ノード(&company;)を見つけ出します。そして、そのノードに対してnextSiblingプロパティを使用し、直後にあるテキストノード「 2023. All rights reserved.」を取得しています。最後に、取得したノードの型がDOMTextであることと、その内容を画面に出力することで、プロパティが正しく機能していることを確認しています。
nextSiblingプロパティは、次の兄弟ノードが存在しない場合にnullを返します。そのため、プロパティの値を取得した後は、必ずnullでないことを確認してから使用してください。確認を怠ると、nullに対して操作しようとしてエラーが発生する原因になります。また、取得できるノードは要素だけでなく、改行やスペースを含むテキストノードの場合もあります。get_class()関数やnodeTypeプロパティで、取得したノードが意図した型であるかを確認することが大切です。このプロパティの挙動はXMLの読み込みオプションにも依存します。例えば、エンティティを展開するオプションを指定すると、サンプルコードのようには動作しなくなる点にも注意が必要です。