【PHP8.x】Dom\Document::adoptNode()メソッドの使い方
adoptNodeメソッドの使い方について、初心者にもわかりやすく解説します。
基本的な使い方
adoptNodeメソッドは、指定されたノードを現在のDom\Documentオブジェクトに「養子として迎え入れる」ことを実行するメソッドです。これは、あるDOMドキュメントに属するノードを、このメソッドを呼び出す別のDom\Documentインスタンスへと所有権を完全に移動させる際に使用されます。具体的には、引数で渡されたノードが元のドキュメントツリーから切り離され、呼び出し元のドキュメントがその新しい所有者となります。
このメソッドの主な目的は、異なるドキュメント間でノードを移動させることです。例えば、複数のXMLファイルやHTML断片を一つのドキュメントに統合する際に、ノードをコピーするのではなく、元の位置から完全に移動させたい場合に非常に有用です。ノードの移動後は、新しいドキュメントのどこにそのノードを配置するかを、appendChildなどの別のメソッドを使って明示的に指定する必要があります。
注意点として、ノードを養子に迎える行為は、元のドキュメントからそのノードを削除することを意味します。また、このメソッドは要素ノードやテキストノードなど、様々な種類のノードに対応していますが、属性ノード(DOMAttr)を直接採用することはできません。ただし、属性を持つ要素ノードを採用した場合、その属性も自動的に新しいドキュメントに移動します。名前空間の情報も適切に保持されるため、異なる名前空間を持つドキュメント間でも安全にノードを扱えます。
構文(syntax)
1<?php 2$targetDocument = new DOMDocument(); 3$sourceDocument = new DOMDocument(); 4$nodeToAdopt = $sourceDocument->createElement('exampleNode'); 5 6// 別のドキュメント($sourceDocument)からノード($nodeToAdopt)を現在のドキュメント($targetDocument)に採用する 7$adoptedNode = $targetDocument->adoptNode($nodeToAdopt); 8?>
引数(parameters)
Dom\Node $node
- Dom\Node $node: 新しく作成されたノードを、このドキュメントに採用(アタッチ)するために指定します
戻り値(return)
Dom\Node
指定されたDom\Documentインスタンスのコンテキストで、他のDom\Documentから移植されたDom\Nodeオブジェクトを返します。
サンプルコード
PHP Dom\Document::adoptNodeでノードを移動する
1<?php 2 3/** 4 * Dom\Document::adoptNode の使用例 5 * 6 * adoptNode メソッドは、ある DOM ドキュメントに属するノードを、 7 * 別の DOM ドキュメントに「採用(adopt)」させ、そのドキュメントの所有とするために使用します。 8 * 元のドキュメントからはノードが切り離されます。 9 * 10 * システムエンジニアを目指す初心者の方へ: 11 * XMLやHTMLのような構造化されたデータをPHPで扱う際に、 12 * あるドキュメントの一部を切り取って別のドキュメントに貼り付けたい場合などに利用できます。 13 * 例えば、複数のXMLファイルから特定の要素を抜き出して、新しいXMLファイルに統合する、といったシナリオで役立ちます。 14 */ 15 16// ドキュメント1を作成し、ノードを含むXMLをロード 17$doc1 = new Dom\Document('1.0', 'UTF-8'); 18$doc1->preserveWhiteSpace = false; 19$doc1->formatOutput = true; 20$doc1->loadXML('<document1><header><title>ドキュメント1のタイトル</title></header><body><item id="itemA">アイテムA (Doc1所属)</item></body></document1>'); 21 22// ドキュメント2を作成し、ノードを追加する場所を含むXMLをロード 23$doc2 = new Dom\Document('1.0', 'UTF-8'); 24$doc2->preserveWhiteSpace = false; 25$doc2->formatOutput = true; 26$doc2->loadXML('<document2><main><content/></main></document2>'); 27 28echo "--- adoptNode 実行前 ---\n"; 29echo "ドキュメント1:\n" . $doc1->saveXML(); 30echo "ドキュメント2:\n" . $doc2->saveXML(); 31 32// ドキュメント1から採用したいノードを取得 33// この例では、idが "itemA" の要素を取得します。 34$nodeToAdopt = $doc1->getElementById('itemA'); 35 36if ($nodeToAdopt instanceof Dom\Node) { 37 echo "--- adoptNode 実行中 ---\n"; 38 echo "ドキュメント1からノード 'itemA' を採用します。\n"; 39 40 // adoptNode メソッドを使用して、ノードをドキュメント2の所有とする 41 // このメソッドは、採用されたノードを返します。 42 $adoptedNode = $doc2->adoptNode($nodeToAdopt); 43 44 // ドキュメント2の <content> 要素に、採用したノードを追加 45 $contentElement = $doc2->getElementsByTagName('content')->item(0); 46 if ($contentElement instanceof Dom\Element) { 47 $contentElement->appendChild($adoptedNode); 48 echo "採用されたノードをドキュメント2の <content> 要素に追加しました。\n"; 49 } else { 50 echo "エラー: ドキュメント2に <content> 要素が見つかりませんでした。\n"; 51 } 52} else { 53 echo "エラー: ドキュメント1から 'itemA' ノードが見つかりませんでした。\n"; 54} 55 56echo "\n--- adoptNode 実行後 ---\n"; 57echo "ドキュメント1 (ノード 'itemA' は削除されている):\n" . $doc1->saveXML(); 58echo "ドキュメント2 (ノード 'itemA' が追加されている):\n" . $doc2->saveXML(); 59 60?>
Dom\Document::adoptNodeメソッドは、PHPでXMLやHTMLなどのDOMツリーを操作する際に利用される重要な機能です。このメソッドは、あるDOMドキュメントに所属しているノードを、別のDOMドキュメントの所有物として「採用(adopt)」するために使用します。システムエンジニアを目指す初心者の方にとっては、複数のXMLファイルから特定の情報を抜き出して一つの新しいXMLファイルにまとめたい場合などに非常に役立つでしょう。
引数にはDom\Node $nodeを指定し、採用したい元のノードを渡します。このノードは、adoptNodeが実行されると元のドキュメントからは自動的に切り離されます。メソッドの戻り値は、新しいドキュメントに「採用」されたDom\Nodeオブジェクトです。この戻り値を使うことで、採用したノードを新しいドキュメント内の適切な位置(例えば、特定の子要素として)に追加することができます。
提供されたサンプルコードでは、document1から取得したitemAというIDを持つ要素が、adoptNodeメソッドによってdocument2に採用され、最終的にdocument2の<content>要素の子として追加される様子が示されています。実行後には、document1からはitemAノードが削除され、document2にはitemAノードが追加されていることが確認できます。このように、ノードの所属ドキュメントを安全かつ効率的に変更できるのがこのメソッドの特長です。
adoptNodeメソッドは、あるDOMドキュメントに属するノードを別のドキュメントの所有とするために使用します。この操作はノードを「移動」させるものであり、元のドキュメントからはそのノードが削除される点にご注意ください。ノードのコピーではありません。また、adoptNodeを実行しただけでは、新しいドキュメントのDOMツリーにノードが自動的に追加されるわけではありません。採用されたノードを実際にツリーに追加するには、appendChildなどのメソッドを別途呼び出す必要があります。ノード取得時や追加先の要素が存在しない場合のエラーを防ぐため、if文やinstanceof演算子で必ず存在チェックを行うようにしてください。
PHP DomDocument::adoptNodeでXMLフラグメントを統合する
1<?php 2 3/** 4 * 複数のXMLフラグメントからノードを収集し、新しいDOMドキュメントにまとめる関数。 5 * ADODBでデータベースから取得されたXMLデータがあると仮定して、Dom\Document::adoptNodeの使用例を示します。 6 * 7 * @param array<string> $xmlFragments XML文字列の配列。これらはADODBを介してデータベースから取得されることを想定。 8 * @return Dom\Document 統合されたDOMドキュメント。 9 */ 10function collectAndAdoptXmlFragments(array $xmlFragments): Dom\Document 11{ 12 // ADODBライブラリはPHP標準ではないため、ここではADODBが返すであろうデータを直接定義します。 13 // 実際のアプリケーションでは、ADODBを使用してデータベースからXMLデータを取得します。 14 // 例: 15 // require_once('adodb/adodb.inc.php'); 16 // $db = ADONewConnection('mysqli'); 17 // $db->Connect('localhost', 'user', 'password', 'database'); 18 // $records = $db->GetAll("SELECT xml_content FROM my_xml_table"); 19 // $xmlFragments = array_column($records, 'xml_content'); // 取得したXMLデータ 20 21 // 最終的にすべてのノードをまとめるための新しいDOMドキュメントを作成します。 22 $mainDoc = new Dom\Document('1.0', 'UTF-8'); 23 // ルート要素 '<items>' を作成し、メインドキュメントに追加します。 24 $root = $mainDoc->createElement('items'); 25 $mainDoc->appendChild($root); 26 27 // 各XMLフラグメントを処理します。 28 foreach ($xmlFragments as $fragmentString) { 29 // 各フラグメントを一時的なDOMドキュメントとしてロードします。 30 // これにより、個々のXML文字列がDOM構造として解析されます。 31 $tempDoc = new Dom\Document('1.0', 'UTF-8'); 32 if (!@$tempDoc->loadXML($fragmentString)) { 33 // XMLパースエラーの場合の処理。ここではエラーログに出力し、次のフラグメントに進みます。 34 error_log("Failed to load XML fragment: " . $fragmentString); 35 continue; 36 } 37 38 // 一時ドキュメントの最上位の要素ノード(例: <item>)を取得します。 39 // adoptNodeはDom\Node型の引数を必要とします。 40 $nodeToAdopt = $tempDoc->documentElement; 41 42 if ($nodeToAdopt instanceof Dom\Node) { 43 // Dom\Document::adoptNode メソッドを使用します。 44 // このメソッドは、別のドキュメントに属するノードを受け取り、 45 // 現在のドキュメントのコンテキストに適合させます。 46 // ノードは元のドキュメントからは削除されます。 47 $adoptedNode = $mainDoc->adoptNode($nodeToAdopt); 48 49 // 採用されたノードをメインドキュメントのルート要素に追加します。 50 // adoptNodeの戻り値もDom\Node型です。 51 if ($adoptedNode instanceof Dom\Node) { 52 $root->appendChild($adoptedNode); 53 } 54 } 55 } 56 57 return $mainDoc; 58} 59 60// ADODBで取得されたと仮定するサンプルXMLデータ 61$sampleXmlDataFromDb = [ 62 '<item id="A"><name>Laptop</name><price>1200</price></item>', 63 '<item id="B"><name>Mouse</name><price>25</price></item>', 64 '<item id="C"><name>Keyboard</name><price>75</price></item>', 65]; 66 67// 関数を呼び出し、複数のXMLフラグメントから統合されたDOMドキュメントを取得します。 68$integratedDocument = collectAndAdoptXmlFragments($sampleXmlDataFromDb); 69 70// 結果を表示するために、XML出力を整形します。 71$integratedDocument->formatOutput = true; 72 73// WebブラウザでXMLとして表示する場合に適切なHTTPヘッダーを設定します。 74header('Content-Type: text/xml'); 75 76// 統合されたDOMドキュメントのXML文字列を出力します。 77echo $integratedDocument->saveXML(); 78 79// このコードを実行すると、次のようなXMLが出力されます。 80// <?xml version="1.0" encoding="UTF-8"?> 81// <items> 82// <item id="A"> 83// <name>Laptop</name> 84// <price>1200</price> 85// </item> 86// <item id="B"> 87// <name>Mouse</name> 88// <price>25</price> 89// </item> 90// <item id="C"> 91// <name>Keyboard</name> 92// <price>75</price> 93// </item> 94// </items> 95
PHP 8のDom\Document::adoptNodeメソッドは、異なるDOMドキュメントに属するノードを、現在のドキュメントのコンテキストへ移動させるために使用されます。このメソッドは、引数として指定されたDom\Node $nodeを、元のドキュメントから切り離し、呼び出し元のDom\Documentオブジェクトに「採用」させます。
例えば、ADODBなどを用いてデータベースから複数のXMLフラグメントをそれぞれ取得し、それらを一つのXMLドキュメントに統合したい場合に非常に役立ちます。サンプルコードでは、個別のXML文字列を一時的なDom\Documentにロードし、その中の最上位のノード(documentElement)をadoptNodeメソッドを使って新しいメインドキュメントへ移動させています。
adoptNodeメソッドの引数Dom\Node $nodeには、移動させたいノードを指定します。このノードは、メソッドが実行されると元のドキュメントからは削除されます。メソッドの戻り値もDom\Node型で、これは採用されたノード自身を返します。この戻り値を利用して、採用したノードをメインドキュメント内の適切な位置(例えば、ルート要素の子として)に追加することで、複数のXML断片から一つのまとまったDOM構造を効率的に構築することが可能です。
このサンプルコードは、複数のXMLフラグメントからノードを収集し、Dom\Document::adoptNodeメソッドを使って一つのDOMドキュメントに統合する処理を示しています。adoptNodeメソッドは、別のドキュメントに属するノードを現在のドキュメントへ「移動」させるため、元のドキュメントからは当該ノードが削除されます。このノードの移動という挙動を理解しておくことが重要です。また、ADODBはPHP標準の機能ではなく、外部ライブラリですので、実際に利用する際には別途インストールが必要です。XMLデータの読み込み時には、パースエラーが発生する可能性も考慮し、エラーを適切に処理しログに出力するなど、堅牢な実装を心がけましょう。