【PHP8.x】Dom\Notation::appendChild()メソッドの使い方
appendChildメソッドの使い方について、初心者にもわかりやすく解説します。
基本的な使い方
appendChildメソッドは、Dom\Notationクラスに属するメソッドで、ノードを子ノードリストの末尾に追加する処理を実行します。具体的には、このメソッドは指定されたノードを、現在のノード(Dom\Notationオブジェクトが表すノード)の子ノードとして追加します。もし、追加しようとするノードが既にドキュメントツリー内に存在する場合、そのノードは現在の位置から削除され、新しい位置(子ノードリストの末尾)に移動します。
このメソッドは、DOM (Document Object Model) ツリー構造を操作する際に非常に重要です。DOMは、HTMLやXMLドキュメントをツリー構造として表現し、プログラムからドキュメントの構造、スタイル、内容を操作するためのAPIを提供します。appendChildメソッドを使用することで、動的にドキュメントの内容を変更したり、新しい要素を既存の要素に追加したりすることが可能になります。
Dom\Notationクラスは、XMLドキュメントのDTD (Document Type Definition) で宣言されたnotationを表すノードです。appendChildメソッドをこのクラスのオブジェクトに対して使用することは一般的ではありません。なぜなら、notationノードは通常、子ノードを持たないからです。しかし、DOMの一般的なノード操作インターフェースの一部として、このメソッドが提供されています。したがって、実際にappendChildメソッドを使用する際は、対象となるノードが子ノードを持つことができるノードタイプであるかを確認することが重要です。例えば、要素ノードやドキュメントノードなどに対しては、appendChildメソッドは頻繁に使用されます。
構文(syntax)
1<?php 2$dom = new DOMDocument(); 3$dom->loadXML('<root><foo/><bar /></root>'); 4 5$notation = $dom->createDocumentType('html', '-//W3C//DTD HTML 4.01 Transitional//EN', 'http://www.w3.org/TR/html4/loose.dtd'); 6$dom->appendChild($notation); 7 8$newNode = $dom->createElement('baz'); 9$dom->documentElement->appendChild($newNode); 10 11echo $dom->saveXML(); 12?>
引数(parameters)
Dom\Node $node
- Dom\Node $node: 追加する子ノードのオブジェクト
戻り値(return)
Dom\Node
appendChildメソッドは、指定したノードを現在のノードの子ノードリストの末尾に追加します。追加されたノード自身を返します。
サンプルコード
PHP DOM appendChild: Notationへの追加を試みる
1<?php 2 3/** 4 * Dom\Notation::appendChild の動作を実演します。 5 * 6 * このメソッドは、仕様上常に DOMException をスローします。 7 * なぜなら、Notation ノードは読み取り専用であり、子ノードを持つことができないためです。 8 * このサンプルコードは、その仕様を実際に確認することを目的としています。 9 */ 10function demonstrateNotationAppendChild(): void 11{ 12 // DTD(文書型定義)内でNotationを定義したXML文字列を用意します。 13 // <!NOTATION gif SYSTEM "image/gif"> がNotationの定義です。 14 $xmlString = <<<XML 15<?xml version="1.0" encoding="UTF-8"?> 16<!DOCTYPE doc [ 17 <!NOTATION gif SYSTEM "image/gif"> 18 <!ELEMENT doc (#PCDATA)> 19]> 20<doc>This is a document.</doc> 21XML; 22 23 // DOMDocumentオブジェクトを作成し、XMLを読み込みます。 24 $dom = new DOMDocument(); 25 $dom->loadXML($xmlString); 26 27 // DocumentTypeノード (<!DOCTYPE ...>) を取得します。 28 // NotationはDocumentTypeノード内に含まれています。 29 $docType = $dom->doctype; 30 31 if ($docType === null || $docType->notations === null) { 32 echo "DTDまたはNotationが見つかりませんでした。\n"; 33 return; 34 } 35 36 // DTDの中から 'gif' という名前のNotationノードを取得します。 37 // この時点で $notation は Dom\Notation オブジェクトになります。 38 $notation = $docType->notations->getNamedItem('gif'); 39 40 if (!$notation instanceof Dom\Notation) { 41 echo "指定されたNotationが見つかりませんでした。\n"; 42 return; 43 } 44 45 echo "取得したNotationノード名: " . $notation->nodeName . "\n\n"; 46 47 try { 48 // Notationノードに子ノードを追加しようと試みます。 49 // この操作は仕様上、常に失敗し例外がスローされます。 50 echo "Dom\\Notation::appendChild() を呼び出します...\n"; 51 $textNode = new DOMText('このテキストは追加できません'); 52 $notation->appendChild($textNode); 53 } catch (DOMException $e) { 54 // 期待通り DOMException がキャッチされます。 55 echo "----------------------------------------\n"; 56 echo "期待通り、例外がキャッチされました。\n"; 57 echo "----------------------------------------\n"; 58 echo "メッセージ: " . $e->getMessage() . "\n"; 59 echo "例外コード: " . $e->code . "\n\n"; 60 61 // DOM_NO_MODIFICATION_ALLOWED_ERR の定数コードは 7 です。 62 if ($e->code === DOM_NO_MODIFICATION_ALLOWED_ERR) { 63 echo "解説: Dom\\Notation ノードは読み取り専用のため、appendChild() で子ノードを追加することはできません。\n"; 64 } 65 } 66} 67 68// 作成した関数を実行します。 69demonstrateNotationAppendChild(); 70 71?>
Dom\Notation::appendChild()は、Notationノードに新しい子ノードを追加するためのメソッドです。引数 $node には、追加したいDom\Nodeオブジェクトを指定します。仕様上、メソッドが成功した場合は追加したノードが戻り値として返されますが、Dom\Notationノードに対して使用すると挙動が異なります。
XMLの仕様では、Notationノードは子ノードを持つことができず、読み取り専用と定められています。そのため、このメソッドを呼び出すとノードの追加は行われず、常にDOMExceptionというエラーが発生します。
サンプルコードでは、まずXML文書のDTD(文書型定義)から特定のNotationノードを取得します。次に、try...catch構文を使い、このNotationノードにテキストノードを追加しようと試みています。この操作は必ず失敗し、意図通りDOMExceptionが捕捉されます。この結果から、Dom\Notationノードが変更不可能なノードであり、子ノードを追加できないという仕様を実際に確認することができます。
このサンプルコードで示されている Dom\Notation::appendChild は、通常のDOM操作とは異なり、仕様上必ずエラーを発生させる特殊な例です。最も重要な注意点は、NotationノードがXMLの文書型定義(DTD)で使われる読み取り専用のノードであり、子ノードを持つことができないという点です。そのため、このメソッドを呼び出すと必ず DOMException という例外が発生します。このコードは、その「必ず失敗する」という仕様をtry-catch構文を使って確認することを目的としています。一般的な要素に子ノードを追加する Dom\Element::appendChild とは全く役割が異なるため、混同しないように注意が必要です。
SimpleXMLからDOMへ、appendChildで子要素を追加する
1<?php 2 3declare(strict_types=1); 4 5/** 6 * SimpleXMLオブジェクトをDOMに変換し、appendChildで子要素を追加する例 7 * 8 * @return void 9 */ 10function addChildToXml(): void 11{ 12 // 操作の基となるXML文字列を定義 13 $xmlString = '<books><book>PHP入門</book></books>'; 14 15 // SimpleXMLオブジェクトを生成 16 $sxe = simplexml_load_string($xmlString); 17 if ($sxe === false) { 18 echo 'XMLの解析に失敗しました。'; 19 return; 20 } 21 22 // SimpleXMLElementをDOMElementに変換 23 // これにより、DOMの強力なメソッドが使えるようになる 24 $domNode = dom_import_simplexml($sxe); 25 if ($domNode === null) { 26 echo 'DOMへの変換に失敗しました。'; 27 return; 28 } 29 30 // DOMDocumentオブジェクトを取得 31 $domDocument = $domNode->ownerDocument; 32 33 // 新しく追加する子要素(<book>)を作成 34 $newBookElement = $domDocument->createElement('book', '新しいPHPの本'); 35 36 // appendChildメソッドを使って、<books>タグの末尾に新しい<book>要素を追加 37 // 戻り値は追加されたノード 38 $appendedNode = $domNode->appendChild($newBookElement); 39 40 // 変更後のXMLを出力 41 // saveXML()は、引数なしでドキュメント全体を、ノードを渡すとそのノード以下を出力する 42 echo $domDocument->saveXML(); 43} 44 45// 関数を実行 46addChildToXml(); 47 48/* 49--- 実行結果 --- 50<?xml version="1.0"?> 51<books><book>PHP入門</book><book>新しいPHPの本</book></books> 52*/
このPHPコードは、既存のXMLデータに新しい要素を追加する方法を示しています。はじめに、simplexml_load_string関数を使ってXML文字列をオブジェクトに変換します。SimpleXMLは手軽ですが、より複雑な操作を行うためにdom_import_simplexml関数でDOMオブジェクトに変換します。これにより、DOMが持つ高機能なメソッド群を利用できるようになります。
次に、createElementメソッドで、XMLに追加したい新しい<book>要素を作成します。ここでの中心となるのがappendChildメソッドです。このメソッドは、指定した親ノード(この例では<books>)の子要素リストの末尾に、引数で渡された新しいノード(作成した<book>要素)を追加します。
appendChildメソッドの引数には、追加したいDom\Nodeオブジェクトを渡します。メソッドの実行が成功すると、戻り値として追加されたDom\Nodeオブジェクトそのものが返されます。もし追加に失敗した場合は false を返します。最後にsaveXMLメソッドで、新しい要素が追加された後のXMLデータ全体を文字列として出力し、変更内容を確認しています。
このサンプルコードは、扱いやすいSimpleXMLと高機能なDOMを連携させている点が特徴です。appendChildはDOMのメソッドであるため、SimpleXMLオブジェクトで直接使うことはできません。dom_import_simplexml関数を使ってDOMオブジェクトへ変換する手順が不可欠です。
注意すべき点は、追加する新しい要素は、必ず追加先の要素と同じXMLドキュメント内で作成する必要があることです。サンプルではownerDocumentプロパティで親ドキュメントを取得し、そのcreateElementメソッドで要素を生成しているため、この条件を満たしています。異なるドキュメントの要素を追加しようとするとエラーになるため注意してください。また、XMLの解析や変換に失敗する場合に備え、simplexml_load_stringなどの関数の戻り値がfalseやnullでないことを確認するエラー処理は、安全なプログラムのために重要です。