【PHP8.x】Dom\HTMLElement::childNodesプロパティの使い方
childNodesプロパティの使い方について、初心者にもわかりやすく解説します。
基本的な使い方
childNodesプロパティは、特定のHTMLまたはXML要素が持つすべての子ノードのリストを保持するプロパティです。このプロパティは、PHPのDOM拡張機能におけるDom\HTMLElementクラスに属しており、HTMLやXMLドキュメントの構造をプログラムから操作する際に非常に重要な役割を果たします。
このプロパティにアクセスすると、Dom\NodeListオブジェクトが返されます。Dom\NodeListは、対象の要素が持つすべての子ノード(例えば、他の要素ノード、テキストノード、コメントノードなど)の集合を表すライブコレクションです。ライブコレクションとは、元のドキュメントツリーの構造が変更されると、NodeListの内容も自動的に更新されることを意味します。これにより、常に最新の子ノードの状態を取得できます。
childNodesプロパティは読み取り専用であり、直接子ノードを追加したり削除したりすることはできません。子ノードの追加や削除、あるいは並び替えを行う場合は、Dom\HTMLElementクラスのappendChild()やremoveChild()といった、より適切なメソッドを使用する必要があります。
このプロパティを使用することで、指定した要素の直下にある全ての子ノードを順番に走査したり、特定の子ノードの情報を取得したりすることが可能になります。例えば、HTMLの<div>要素の子ノードを取得して、その中の<p>要素や<img>要素などを識別し、それぞれの内容を処理するような場面で活用されます。システムエンジニアがWebページの内容を動的に変更したり、XMLデータから特定の情報を抽出したりする際に、DOMツリーの構造を理解し、childNodesプロパティを適切に活用することは、基盤となる重要なスキルとなります。
構文(syntax)
1<?php 2// Dom\Document クラスを使用してHTMLドキュメントを読み込みます。 3$document = new \Dom\Document(); 4$document->loadHtml('<html><body><div id="exampleDiv"><p>これは段落です。</p>テキストノード<!--これはコメントです--></div></body></html>'); 5 6// id="exampleDiv" を持つ要素を取得します。 7// 取得されるオブジェクトは \Dom\Element のインスタンスですが、 8// これは HTML 要素を表し、\Dom\HTMLElement クラスが提供するプロパティを利用できます。 9$htmlElement = $document->getElementById('exampleDiv'); 10 11// $htmlElement の childNodes プロパティにアクセスし、子ノードの Dom\NodeList を取得します。 12$children = $htmlElement->childNodes; 13 14// 取得した子ノードのリストを反復処理し、それぞれのノードの情報を表示します。 15foreach ($children as $node) { 16 echo "ノード名: " . $node->nodeName; 17 if ($node->nodeType === \Dom\Node::TEXT_NODE || $node->nodeType === \Dom\Node::COMMENT_NODE) { 18 echo ", 内容: '" . trim($node->textContent) . "'"; 19 } 20 echo "\n"; 21} 22?>
引数(parameters)
引数なし
引数はありません
戻り値(return)
DOMNodeList
Dom\HTMLElementクラスのchildNodesプロパティは、その要素の子ノードをすべて格納したDOMNodeListを返します。DOMNodeListは、子ノードのコレクションであり、配列のようにアクセスしたり、ループ処理を行うことができます。
サンプルコード
PHP DOM childNodesで子ノードを取得する
1<?php 2 3/** 4 * Dom\HTMLElement::childNodes の使用方法をデモンストレーションします。 5 * 6 * この関数は、シンプルなHTML構造を作成し、特定の要素を見つけ、 7 * その直接の子ノードをすべて取得して、種類と名前を出力します。 8 * childNodes は要素ノードだけでなく、テキストノードやコメントノードなども含みます。 9 */ 10function demonstrateDomChildNodes(): void 11{ 12 // 1. 新しい DOMDocument インスタンスを作成します。 13 // PHP の Dom エクステンションは、HTMLやXML文書をオブジェクトとして操作するために使用されます。 14 $dom = new DOMDocument(); 15 16 // 2. 操作対象となるHTMLコンテンツをロードします。 17 // `loadHTML` メソッドは、文字列からHTMLをパースしてDOMツリーを構築します。 18 $html = <<<HTML 19<!DOCTYPE html> 20<html> 21<head> 22 <title>ChildNodes Demo</title> 23</head> 24<body> 25 <div id="container"> 26 <!-- div要素の直下にある様々な種類のノードを確認します --> 27 <p>最初のパラグラフです。</p> 28 これはプレーンなテキストです。 29 <span>これはスパン要素です。</span> 30 <!-- これはコメントノードです --> 31 <ul> 32 <li>リストアイテム1</li> 33 <li>リストアイテム2</li> 34 </ul> 35 </div> 36</body> 37</html> 38HTML; 39 $dom->loadHTML($html); 40 41 // 3. ID を使って対象の HTMLElement を見つけます。 42 // `getElementById` は DOMElement オブジェクトを返します。 43 // DOMElement は Dom\HTMLElement クラスのサブクラスです。 44 $containerElement = $dom->getElementById('container'); 45 46 if (!$containerElement) { 47 echo "エラー: ID 'container' を持つ要素が見つかりませんでした。\n"; 48 return; 49 } 50 51 echo "--- ID 'container' を持つ要素の子ノード一覧 ---\n"; 52 53 // 4. `childNodes` プロパティにアクセスします。 54 // このプロパティは DOMNodeList を返します。DOMNodeList には、 55 // 指定された要素のすべての直接の子ノード(要素、テキスト、コメントなど)が含まれます。 56 $children = $containerElement->childNodes; 57 58 // 5. DOMNodeList をループし、各子ノードの情報を表示します。 59 // nodeType を使用してノードの種類を判別できます。 60 foreach ($children as $node) { 61 $nodeTypeString = match ($node->nodeType) { 62 XML_ELEMENT_NODE => '要素ノード (Element)', 63 XML_TEXT_NODE => 'テキストノード (Text)', 64 XML_COMMENT_NODE => 'コメントノード (Comment)', 65 XML_CDATA_SECTION_NODE => 'CDATAセクションノード (CDATA Section)', 66 XML_DOCUMENT_NODE => '文書ノード (Document)', 67 XML_DOCUMENT_TYPE_NODE => '文書型ノード (Document Type)', 68 XML_PI_NODE => '処理命令ノード (Processing Instruction)', 69 default => 'その他のノード', 70 }; 71 72 // ノードの名前と値(テキストノードの場合は内容)を出力します。 73 // テキストノードの値は、改行やインデントのための空白文字が含まれることが多いです。 74 $nodeValueDisplay = trim(substr($node->nodeValue, 0, 50)); 75 if (strlen($node->nodeValue) > 50) { 76 $nodeValueDisplay .= '...'; 77 } 78 79 printf( 80 "- タイプ: %s (名前: '%s', 値: '%s')\n", 81 $nodeTypeString, 82 $node->nodeName, 83 $nodeValueDisplay 84 ); 85 } 86 echo "---------------------------------------------------\n"; 87} 88 89// デモンストレーション関数を実行します。 90demonstrateDomChildNodes(); 91 92?>
Dom\HTMLElement::childNodesは、PHP 8 のDOM拡張機能の一部で、HTMLドキュメント内の特定の要素が持つ「直接の子ノード」すべてを取得するためのプロパティです。このプロパティに引数は不要で、呼び出すとDOMNodeListというオブジェクトが戻り値として返されます。DOMNodeListは、取得した子ノードを一覧で保持するコレクションであり、配列のように各ノードにアクセスできます。
サンプルコードでは、まずシンプルなHTMLコンテンツをDOMDocumentオブジェクトに読み込み、操作可能な形にしています。次に、getElementByIdメソッドを使って、IDが「container」である特定のdiv要素を見つけ出します。この見つけ出したdiv要素に対してchildNodesプロパティを利用すると、そのdiv要素直下のすべての子ノードが取得されます。
ここでのポイントは、childNodesが単にpタグやulタグのような「要素ノード」だけではなく、HTML上の改行や空白、実際のテキストコンテンツである「テキストノード」、さらには「コメントノード」までも含む点です。コードは、取得したDOMNodeList内の各ノードを一つずつ丁寧にループ処理し、nodeTypeプロパティでノードの種類を判別しながら、その名前や値(内容)を具体的に出力しています。これにより、childNodesプロパティがどのような種類のノードをどのようにリストアップするのか、その挙動を明確に理解することができます。
Dom\HTMLElement::childNodesは、親要素の直下にあるすべてのノード(要素、テキスト、コメントなど)を取得します。HTMLソースの改行やインデントもテキストノードとして取得されるため、要素ノードだけを扱いたい場合は、取得後にnodeTypeでフィルタリングが必要です。また、getElementByIdなどで要素を取得する際は、見つからない場合にnullが返されるため、必ず取得結果をチェックし、エラーハンドリングをしてください。childNodesが返すDOMNodeListは「ライブコレクション」で、元のDOMツリーが変更されると内容も自動的に更新されます。ループ中にDOMツリーを操作する際は、この特性を理解して慎重にコードを記述してください。テキストノードの値はtrim()などで整形すると扱いやすくなります。
PHPでXPathとchildNodesを使い要素の子ノードを取得する
1<?php 2 3/** 4 * HTML文字列から指定された要素の子ノードを取得し、情報を表示する関数。 5 * DOMXPathとDom\HTMLElement::childNodesプロパティ(またはその親クラスであるDOMElementのchildNodes)の使用例を示します。 6 * システムエンジニアを目指す初心者にも理解しやすいように、詳細なコメントを付けています。 7 * 8 * @param string $html HTML文字列 9 * @param string $xpathExpression XPath式で親要素を選択するための式 10 * @return void 11 */ 12function processHtmlChildNodes(string $html, string $xpathExpression): void 13{ 14 // DOMDocumentオブジェクトを作成し、HTMLをロードするための準備をします。 15 $dom = new DOMDocument(); 16 17 // HTMLパース時のエラーを抑制し、DOMDocumentが自動で<html>, <head>, <body>タグを追加しないように設定します。 18 // LIBXML_HTML_NOIMPLIED: 暗黙のHTML/BODY要素を追加しない 19 // LIBXML_HTML_NODEFDTD: デフォルトのDTDを追加しない 20 // loadHTML は成功時に true、失敗時に false を返します。@ を付けて警告を抑制しています。 21 if (@$dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD)) { 22 // DOMXPathオブジェクトを作成します。これにより、XPathクエリを使用してDOMツリー内の要素を検索できます。 23 $xpath = new DOMXPath($dom); 24 25 // XPath式で指定された親要素を検索します。 26 // queryメソッドは、一致するすべてのノードを含むDOMNodeListオブジェクトを返します。 27 $elements = $xpath->query($xpathExpression); 28 29 // 結果がDOMNodeListであり、かつ一つ以上の要素が見つかった場合 30 if ($elements instanceof DOMNodeList && $elements->length > 0) { 31 foreach ($elements as $parent_node) { 32 // 取得したノードがDOMElementのインスタンスであることを確認します。 33 // PHP 8で導入されたDom\HTMLElementクラスもDOMElementを継承しており、childNodesプロパティを持ちます。 34 // したがって、このコードはDom\HTMLElementのインスタンスに対しても同様に機能します。 35 if ($parent_node instanceof DOMElement) { 36 echo "--- 親要素: '{$parent_node->nodeName}' (".($parent_node->hasAttribute('id') ? "id='{$parent_node->getAttribute('id')}'" : "IDなし").") の子ノード一覧 ---\n"; 37 38 // childNodesプロパティを使用して、親ノードの直接の子ノードリストを取得します。 39 // childNodesは、要素、テキスト、コメントなど、すべてのタイプの子ノードを含むDOMNodeListオブジェクトを返します。 40 $children = $parent_node->childNodes; 41 42 if ($children->length === 0) { 43 echo " 子ノードはありません。\n"; 44 } else { 45 foreach ($children as $child_node) { 46 echo " - ノードタイプ: {$child_node->nodeName} (XML_NODE_TYPE: {$child_node->nodeType}), 値: '"; 47 48 // ノードのタイプに応じて、その値を表示します。 49 switch ($child_node->nodeType) { 50 case XML_TEXT_NODE: // テキストノードの場合 51 echo trim($child_node->nodeValue); 52 break; 53 case XML_ELEMENT_NODE: // 要素ノード(例: <p>, <h1>)の場合 54 echo $child_node->nodeName; 55 break; 56 case XML_COMMENT_NODE: // コメントノード(例: <!-- コメント -->)の場合 57 echo '#コメント'; 58 break; 59 default: 60 echo '(その他のノードタイプ)'; 61 } 62 echo "'\n"; 63 } 64 } 65 66 // キーワード「xpath childnodes」をより強調するため、XPathを使って特定の要素ノードのみを選択する例を示します。 67 echo "\n--- XPathで '{$parent_node->nodeName}' 内の特定の要素(例: pタグ)を取得 ---\n"; 68 // XPathは現在のノードを基準にするため、'.' を使い、その子要素である 'p' タグを選択します。 69 $specific_children_xpath = $xpath->query('./p', $parent_node); 70 if ($specific_children_xpath instanceof DOMNodeList && $specific_children_xpath->length > 0) { 71 foreach ($specific_children_xpath as $specific_child) { 72 if ($specific_child instanceof DOMElement) { 73 echo " - XPathで取得したpタグ: <{$specific_child->nodeName}>, 内容: '{$specific_child->textContent}'\n"; 74 } 75 } 76 } else { 77 echo " XPath './p' に一致する子要素は見つかりませんでした。\n"; 78 } 79 echo "\n"; 80 } 81 } 82 } else { 83 echo "指定されたXPath式 '{$xpathExpression}' に一致する要素は見つかりませんでした。\n"; 84 } 85 } else { 86 echo "HTMLのロードに失敗しました。\n"; 87 } 88} 89 90// サンプルHTML文字列を定義します。 91$sampleHtml = <<<HTML 92<!DOCTYPE html> 93<html> 94<head> 95 <title>サンプルページ</title> 96</head> 97<body> 98 <div id="container"> 99 <h1>ようこそ!</h1> 100 <p>これは最初の段落です。</p> 101 <p><b>Bold</b>テキストを含む2番目の段落。</p> 102 <!-- これはコメントです --> 103 <ul> 104 <li>リストアイテム1</li> 105 <li>リストアイテム2</li> 106 </ul> 107 テキストノードもここにあります。 108 <span>これはスパンタグです</span> 109 </div> 110 <div class="another-container"> 111 <p>別のコンテナの段落。</p> 112 </div> 113</body> 114</html> 115HTML; 116 117// 例1: id="container" のdiv要素の子ノードを取得し、情報を表示します。 118echo "--- 例1: IDが 'container' のdiv要素の子ノードを処理 ---\n"; 119processHtmlChildNodes($sampleHtml, "//div[@id='container']"); 120 121echo "\n-----------------------------------------------------\n\n"; 122 123// 例2: 2番目のp要素の子ノードを取得し、情報を表示します。 124// このp要素はテキストノードとb要素ノードを含んでいます。 125echo "--- 例2: 2番目のp要素の子ノードを処理 ---\n"; 126processHtmlChildNodes($sampleHtml, "//p[2]"); 127
このPHPコードは、HTML文字列から特定の要素の子ノードを取得し、その情報を表示する方法を示しています。まず、HTMLをDOMDocumentに読み込み、DOMXPathを使って指定されたXPath式で親となる要素を検索します。親要素が見つかると、Dom\HTMLElement::childNodesプロパティ(または親クラスであるDOMElementのchildNodes)を使用して、その親要素の直接の子ノードすべてをDOMNodeListとして取得します。childNodesプロパティは引数を取りません。戻り値のDOMNodeListには、要素ノード、テキストノード、コメントノードなど、様々なタイプの子ノードが含まれます。コードは、このDOMNodeListをループ処理し、各子ノードのタイプ(要素名、テキスト、コメントなど)と内容を識別して出力しています。さらに、DOMXPathを使って特定の子要素(例:pタグ)のみを選択し、childNodesプロパティで取得したすべてのノードの中から、特定の種類のノードだけを効率的に検索できることも示されています。これにより、Webページの構造を解析し、必要な情報を取り出すための基本的な手順を学ぶことができます。
Dom\HTMLElement::childNodesプロパティは、要素だけでなく、HTMLの整形による空白のテキストノードやコメントノードを含む、全ての直接の子ノードを返します。そのため、目的のノードタイプをXML_TEXT_NODEなどで判別し、テキストノードはtrim()で余分な空白を除去する処理を検討してください。要素ノードのみが必要な場合は、XPathやDOMElement::childrenプロパティの利用も検討できます。DOMDocument::loadHTML関数はHTMLパース時に警告を出すことがあるため、@演算子で抑制しつつ、戻り値を必ずチェックし、適切なエラーハンドリングを行うことが重要です。Dom\HTMLElementはDOMElementを継承しており、基本的なDOM操作は共通で利用できます。