【PHP8.x】DOMDocument::previousSiblingプロパティの使い方
previousSiblingプロパティの使い方について、初心者にもわかりやすく解説します。
基本的な使い方
previousSiblingプロパティは、DOMDocumentオブジェクトにおける、指定されたノードの直前の兄弟ノードを返します。兄弟ノードとは、同じ親ノードを持つノードのことです。もし指定されたノードが親ノードの最初の子ノードである場合、つまり直前の兄弟ノードが存在しない場合、このプロパティはnullを返します。
このプロパティは読み取り専用であり、値を設定することはできません。ノードの構造をDOMDocument内で移動したり、特定のノードの前にあるノードを特定したりする際に非常に役立ちます。
具体的な使用例としては、XMLドキュメントやHTMLドキュメントをPHPで操作する際に、ある要素の直前の要素にアクセスしたい場合に利用できます。例えば、リスト構造において、現在処理しているリストアイテムの前のアイテムの情報を取得したい場合などに活用できます。
DOMDocumentクラスの他のプロパティやメソッドと組み合わせて使用することで、ドキュメント内のノードを効率的に操作し、必要な情報を抽出したり、ドキュメント構造を修正したりすることが可能になります。特に、DOMDocumentのchildNodesプロパティやparentNodeプロパティと組み合わせて使用することで、ドキュメント内のノードを辿り、必要なノードを特定する処理を実装できます。
構文(syntax)
1DOMNode|null DOMDocument::$previousSibling;
引数(parameters)
引数なし
引数はありません
戻り値(return)
DOMNode|null
このプロパティは、現在のノードの直前の兄弟ノードを表すDOMNodeオブジェクト、または直前の兄弟ノードが存在しない場合はnullを返します。
サンプルコード
PHP DOMDocument: previousSiblingで前の兄弟ノードを取得する
1<?php 2 3/** 4 * DOMNode::previousSibling プロパティの使用方法を示すサンプルコード。 5 * 指定されたノードの前の兄弟ノードを取得します。 6 * システムエンジニアを目指す初心者向けに、簡潔かつ分かりやすく記述されています。 7 */ 8function demonstrateDomPreviousSibling(): void 9{ 10 // 新しい DOMDocument インスタンスを作成 11 $dom = new DOMDocument(); 12 13 // XMLコンテンツを読み込む 14 // このXMLは、兄弟ノードの動作を明確に示すためにシンプルにしています。 15 // HTMLでも同様に動作しますが、空白がTextノードとして扱われることがあるため 16 // XMLの方が「要素の兄弟」を理解しやすい場合があります。 17 $xmlContent = <<<XML 18<root> 19 <item id="first">最初のアイテム</item> 20 <item id="second">2番目のアイテム</item> 21 <item id="third">3番目のアイテム</item> 22</root> 23XML; 24 $dom->loadXML($xmlContent); 25 26 // すべての 'item' 要素を取得します。 27 // getElementsByTagName は DOMNodeList を返します。 28 $items = $dom->getElementsByTagName('item'); 29 30 // ターゲットとなるノードを選択します。 31 // ここでは、3番目のアイテム(インデックスは2)をターゲットとします。 32 /** @var DOMElement|null $targetNode */ 33 $targetNode = $items->item(2); // "3番目のアイテム" 34 35 if ($targetNode) { 36 echo "ターゲットノード: '{$targetNode->textContent}' (要素名: {$targetNode->nodeName})\n"; 37 38 // previousSibling プロパティを使用して、ターゲットノードの前の兄弟ノードを取得します。 39 // 戻り値は DOMNode または null です。 40 /** @var DOMNode|null $previousSiblingNode */ 41 $previousSiblingNode = $targetNode->previousSibling; 42 43 if ($previousSiblingNode) { 44 echo "前の兄弟ノードが見つかりました。\n"; 45 echo " ノードタイプ: {$previousSiblingNode->nodeName}\n"; 46 echo " ノード値 (textContent): '{$previousSiblingNode->textContent}'\n"; 47 // DOMElementの場合、attributesから属性値も取得できます 48 if ($previousSiblingNode instanceof DOMElement) { 49 echo " id属性: {$previousSiblingNode->getAttribute('id')}\n"; 50 } 51 } else { 52 echo "ターゲットノード '{$targetNode->textContent}' には前の兄弟ノードがありません。\n"; 53 } 54 } else { 55 echo "ターゲットノードが見つかりませんでした。\n"; 56 } 57} 58 59// 関数を実行して、previousSibling の動作を確認します。 60demonstrateDomPreviousSibling();
このサンプルコードは、PHP 8におけるDOMNodeクラスのpreviousSiblingプロパティの基本的な使い方を示しています。このプロパティは、ドキュメント構造内の特定のノードに対して、その直前に位置する兄弟ノードを取得するために使用されます。引数は必要なく、対象のノードから直接このプロパティを参照するだけで前の兄弟ノードにアクセスできます。
サンプルコードでは、まずXML形式の文字列をDOMDocumentに読み込み、解析可能なドキュメント構造を構築しています。次に、getElementsByTagNameメソッドを使用してXML内のすべてのitem要素を取得し、その中から「3番目のアイテム」をターゲットノードとして選択しています。
選択されたターゲットノードに対してpreviousSiblingプロパティを用いると、そのノードの直前の兄弟ノードが返されます。このプロパティの戻り値は、前の兄弟ノードが存在すればDOMNodeオブジェクト、存在しなければnullとなります。コードではこの戻り値をチェックし、ノードが見つかった場合にはそのノードの種類やテキスト内容、id属性などの情報を表示しています。このように、previousSiblingプロパティを利用することで、XMLやHTMLなどのドキュメントツリーをたどり、特定のノードの前にある要素を効率的に取得することが可能です。
DOMNode::previousSiblingプロパティは、前の兄弟ノードが存在しない場合や、ターゲットノードが親の最初の子要素である場合はnullを返しますので、取得後には必ずnullチェックを行うようにしてください。HTMLドキュメントを解析する際、要素間の改行やスペースがDOMTextノードとして認識され、意図しない空白ノードがpreviousSiblingとして取得されることがあります。特にHTMLではこの点に注意が必要です。また、previousSiblingの戻り値は汎用的なDOMNode型であるため、getAttributeなどのDOMElement特有のメソッドを利用する際は、instanceof DOMElementで対象が要素ノードであるかを確認すると、より安全なコードになります。
PHP DOMDocument::previousSiblingで兄弟ノードを取得する
1<?php 2 3/** 4 * DOMNode::previousSibling プロパティの使用例を示します。 5 * このプロパティは、現在のノードの直前の兄弟ノードを返します。 6 * 空白文字や改行、コメントなどもテキストノードやコメントノードとして扱われる点に注意が必要です。 7 * 8 * DOMDocument オブジェクト自体はドキュメントのルートノードであるため、その previousSibling プロパティは常に null を返します。 9 * 通常、このプロパティはドキュメント内の他の要素やテキストノードに対して使用されます。 10 */ 11function demonstratePreviousSibling(): void 12{ 13 // DOMDocumentオブジェクトを作成し、HTML文字列をロード 14 $dom = new DOMDocument(); 15 // LIBXML_HTML_NOIMPLIED と LIBXML_HTML_NODEFDTD は、 16 // PHPがHTMLをロードする際に自動で追加する<html>, <body>タグやDOCTYPE宣言などを抑制し、 17 // サンプルコードのDOM構造を分かりやすくします。 18 $html = <<<HTML 19<div> 20 <!-- これはコメントノードです --> 21 <p>最初の段落</p> 22 <span>途中の要素</span> 23 <p>二番目の段落</p> 24</div> 25HTML; 26 $dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); 27 28 // XPathを使ってDOMツリーを探索するためのDOMXPathオブジェクトを作成 29 $xpath = new DOMXPath($dom); 30 31 // 「二番目の段落」というテキストを持つ<p>要素を取得 32 $secondParagraph = $xpath->query('//p[text()="二番目の段落"]')->item(0); 33 34 if ($secondParagraph instanceof DOMNode) { 35 echo "現在のノード: '{$secondParagraph->nodeValue}' (ノード名: {$secondParagraph->nodeName})\n\n"; 36 37 // previousSiblingプロパティを使用して直前の兄弟ノードを取得 38 $previousSibling = $secondParagraph->previousSibling; 39 40 if ($previousSibling instanceof DOMNode) { 41 echo "--- 直前の兄弟ノード --- \n"; 42 echo " ノード名: {$previousSibling->nodeName}\n"; 43 // ノードタイプの一例: 1 (要素ノード), 3 (テキストノード), 8 (コメントノード) 44 echo " ノードタイプ: {$previousSibling->nodeType}\n"; 45 // テキストノードの場合、値は空白を含むことがあるため trim() で整形 46 echo " ノード値 (トリム済): '" . trim($previousSibling->nodeValue) . "'\n"; 47 echo " 解説: '二番目の段落' の直前の兄弟は、'途中の要素' の <span> 要素の後の改行と空白文字です(テキストノード)。\n\n"; 48 } else { 49 echo " 直前の兄弟ノードは存在しません。\n\n"; 50 } 51 } else { 52 echo "指定されたノード(二番目の段落)が見つかりませんでした。\n\n"; 53 } 54 55 echo "--------------------------------------------------\n\n"; 56 57 // 「最初の段落」というテキストを持つ<p>要素を取得 58 $firstParagraph = $xpath->query('//p[text()="最初の段落"]')->item(0); 59 60 if ($firstParagraph instanceof DOMNode) { 61 echo "現在のノード: '{$firstParagraph->nodeValue}' (ノード名: {$firstParagraph->nodeName})\n\n"; 62 63 $previousSiblingForFirst = $firstParagraph->previousSibling; 64 65 if ($previousSiblingForFirst instanceof DOMNode) { 66 echo "--- 直前の兄弟ノード --- \n"; 67 echo " ノード名: {$previousSiblingForFirst->nodeName}\n"; 68 echo " ノードタイプ: {$previousSiblingForFirst->nodeType}\n"; 69 echo " ノード値 (トリム済): '" . trim($previousSiblingForFirst->nodeValue) . "'\n"; 70 echo " 解説: '最初の段落' の直前の兄弟は、HTML内の '<!-- これはコメントノードです -->' のコメントノードです。\n\n"; 71 } else { 72 echo " 直前の兄弟ノードは存在しません。\n\n"; 73 } 74 } else { 75 echo "指定されたノード(最初の段落)が見つかりませんでした。\n\n"; 76 } 77} 78 79// 関数を実行 80demonstratePreviousSibling(); 81
PHPのDOMNode::previousSiblingプロパティは、HTMLやXML文書の構造(DOMツリー)を操作する際に、現在のノードの直前にある兄弟ノードを取得するために使用されます。このプロパティは引数を持ちませんが、戻り値として直前の兄弟ノードがDOMNodeオブジェクトとして返されるか、直前の兄弟ノードが存在しない場合はnullが返されます。
サンプルコードでは、HTMLからDOMツリーを構築し、特定のノードからpreviousSiblingを探索しています。「二番目の段落」という<p>要素のpreviousSiblingを取得すると、その直前の要素である<span>途中の要素</span>の直後に存在する改行や空白文字がテキストノードとして取得されます。同様に、「最初の段落」という<p>要素のpreviousSiblingは、その直前のコメントノードである<!-- これはコメントノードです -->を返しています。
このように、previousSiblingプロパティは、要素ノードだけでなく、空白文字や改行からなるテキストノード、あるいはコメントノードなども兄弟ノードとして認識し、それらを返します。そのため、DOMツリーを探索する際には、返されたノードのタイプや値を確認することが重要です。このプロパティは、特定のノードからDOMツリーの前方向へ兄弟ノードを辿る際に非常に役立ちます。
previousSiblingプロパティは、現在のノードの直前の兄弟ノードを返しますが、HTMLのソースコードに含まれる改行や空白もテキストノードとして扱われる点に注意が必要です。そのため、見た目では何も存在しないように見えても、テキストノードが返されることがあります。直前の兄弟ノードが存在しない場合はnullを返すため、必ず取得結果がnullでないか、またはDOMNodeのインスタンスであるかをチェックしてから使用してください。DOMDocumentオブジェクト自体はルートノードであるため、そのpreviousSiblingプロパティは常にnullを返します。サンプルコードのようにloadHTML関数にオプションを使用すると、PHPが自動で追加する<html>や<body>などの要素を抑制し、DOM構造をシンプルに扱えます。