【PHP8.x】DOMEntity::childNodesプロパティの使い方
childNodesプロパティの使い方について、初心者にもわかりやすく解説します。
基本的な使い方
childNodesプロパティは、DOMNodeListオブジェクトを保持するプロパティです。このプロパティは、PHPのDOM拡張機能において、XMLドキュメントの構造を操作する際に使用されるDOMEntityクラスに属しています。
DOMEntityクラスは、XMLドキュメントのエンティティ(実体)の定義を表します。エンティティとは、XMLドキュメント内で再利用可能なデータの塊に名前を付けて定義する仕組みです。例えば、&のような文字参照や、DTD(Document Type Definition)内で定義される複雑な構造を持つ外部エンティティなどがこれにあたります。
DOMEntityオブジェクトのchildNodesプロパティは、そのエンティティの定義内に含まれる全ての子ノードのリストをDOMNodeListとして返します。このDOMNodeListは、子ノードの集合を読み取り専用で扱うためのインターフェースを提供します。具体的には、エンティティ定義が例えば <p>Hello, <strong>World!</strong></p> のような構造を持つ場合、childNodesプロパティは<p>要素ノードをリストとして提供します。このプロパティは、XMLドキュメントの型定義(DTDなど)に記述されたエンティティの内部構造をプログラム的に解析したい場合に特に有用です。
しかし、DOMEntityオブジェクト自体は、XMLドキュメントの実際のDOMツリー内に直接挿入されるノードではありません。これはあくまで「エンティティの定義そのもの」を表すものです。実際のドキュメントコンテンツでエンティティが参照された場合(例: &myEntity;)、その場所にはエンティティ参照を表すDOMEntityReferenceノード、またはパーサーによって展開されたエンティティの実際のコンテンツが配置されます。したがって、DOMEntity::childNodesプロパティは、エンティティ参照が展開された結果のノードではなく、エンティティの「定義」が持つ子ノードをリストアップする目的で使用されます。このプロパティを通じて、XMLドキュメントの構造やその型定義におけるエンティティの構成を詳細に分析することが可能になります。
構文(syntax)
1<?php 2$dom = new DOMDocument(); 3$dom->loadXML('<!DOCTYPE root [<!ENTITY example "Hello <b>World</b>!">]><root/>'); 4 5// "example" という名前のエンティティを取得 6$entity = $dom->doctype->entities->getNamedItem('example'); 7 8if ($entity) { 9 // DOMEntity::childNodes プロパティにアクセス 10 $nodes = $entity->childNodes; 11 12 // 子ノードを順に表示 13 foreach ($nodes as $node) { 14 echo $node->nodeName . ": " . $node->nodeValue . "\n"; 15 } 16} 17?>
引数(parameters)
引数なし
引数はありません
戻り値(return)
DOMNodeList
DOMEntityオブジェクトの子ノードをDOMNodeListオブジェクトとして取得します。このリストには、エンティティのすべての子ノードが含まれます。
サンプルコード
PHP DOM childNodesでエンティティの子ノードを取得する
1<?php 2 3/** 4 * DOMEntityのchildNodesプロパティの使用例を示します。 5 * 6 * この関数は、DTD(文書型定義)で定義されたエンティティを取得し、 7 * その子ノードのリストを走査して内容を出力します。 8 * エンティティがテキストノードや要素ノードを子として持つ様子を確認できます。 9 */ 10function showEntityChildNodes(): void 11{ 12 // DTD内で、テキストと要素を子に持つエンティティを定義したXML文字列 13 $xmlString = <<<XML 14 <?xml version="1.0" encoding="utf-8"?> 15 <!DOCTYPE root [ 16 <!ENTITY sampleEntity "これはテキストと <b>太字要素</b> です。"> 17 ]> 18 <root>&sampleEntity;</root> 19 XML; 20 21 // DOMDocumentオブジェクトを生成してXMLを読み込む 22 $doc = new DOMDocument(); 23 $doc->loadXML($xmlString); 24 25 // DTD(文書型定義)部分を取得 26 $doctype = $doc->doctype; 27 if (!$doctype) { 28 echo 'DTDが見つかりません。'; 29 return; 30 } 31 32 // DTD内のエンティティ定義のリストを取得 33 $entities = $doctype->entities; 34 35 // 'sampleEntity' という名前のエンティティ (DOMEntity) を取得 36 $entity = $entities->getNamedItem('sampleEntity'); 37 38 // DOMEntityのchildNodesプロパティにアクセスし、子ノードを出力 39 if ($entity instanceof DOMEntity) { 40 echo "エンティティ '{$entity->nodeName}' の子ノード一覧:\n"; 41 echo "------------------------------------\n"; 42 43 // childNodesプロパティはDOMNodeListを返す 44 $childNodes = $entity->childNodes; 45 46 // 子ノードのリストをループ処理 47 foreach ($childNodes as $childNode) { 48 // ノードの種類に応じて出力を整形 49 if ($childNode instanceof DOMElement) { 50 // 要素ノードの場合 (例: <b>) 51 printf( 52 "- 要素ノード: <%s> (内容: '%s')\n", 53 $childNode->nodeName, 54 $childNode->textContent 55 ); 56 } elseif ($childNode instanceof DOMText) { 57 // テキストノードの場合 58 printf( 59 "- テキストノード: '%s'\n", 60 trim($childNode->nodeValue) 61 ); 62 } 63 } 64 } else { 65 echo "エンティティ 'sampleEntity' が見つかりませんでした。\n"; 66 } 67} 68 69// 関数を実行 70showEntityChildNodes();
このPHPサンプルコードは、DOMEntityクラスのchildNodesプロパティを使用して、XML文書のDTD(文書型定義)で定義されたエンティティが持つ子ノードの一覧を取得する方法を示します。
childNodesは、エンティティが直接内包している全ての子ノードを取得するためのプロパティです。このプロパティは引数を取りません。戻り値として、複数のノードが格納されたDOMNodeListオブジェクトを返します。このDOMNodeListは、foreach文を使ってリスト内の各ノードを順番に処理するのに適しています。
サンプルコードでは、まずDTD内でテキストと<b>要素を含むsampleEntityというエンティティを定義します。そして、このエンティティを表すDOMEntityオブジェクトを取得し、childNodesプロパティにアクセスしています。エンティティの定義内容である「これはテキストと <b>太字要素</b> です。」は、テキスト部分と<b>要素部分に分解され、それぞれがテキストノードや要素ノードとしてDOMNodeListに格納されます。ループ処理によって各ノードの種類を判別し、その内容を出力することで、エンティティの内部構造を詳細に確認できます。
childNodesプロパティは、テキストやHTMLタグなど、すべての子ノードを含むリスト(DOMNodeList)を返します。このリストはforeachで直接繰り返し処理ができます。注意点として、エンティティ内の文字列は一つの塊ではなく、サンプルコードの<b>タグとその前後のテキストのように、複数のノードに分割されて格納されます。また、タグ間の改行や空白文字だけでもテキストノードとして扱われることがあるため、処理の際には意図しない空のノードが含まれる可能性を考慮する必要があります。なお、childNodesはプロパティのため、メソッドのように()を付けずにアクセスしてください。
PHP XPath childNodesで子ノードを処理する
1<?php 2 3declare(strict_types=1); 4 5/** 6 * XPathで取得したノードの子ノードリスト(childNodes)を処理するサンプル関数 7 * 8 * DOMNode::childNodes プロパティは、要素ノードだけでなく、 9 * テキストノード(改行やインデントの空白も含む)やコメントノードもすべて含んだ 10 * DOMNodeList を返します。 11 */ 12function processChildNodesWithXPath(): void 13{ 14 // サンプルとなるXML文字列 15 $xmlString = <<<XML 16<?xml version="1.0" encoding="UTF-8"?> 17<bookstore> 18 <book category="cooking"> 19 <title lang="en">Everyday Italian</title> 20 <author>Giada De Laurentiis</author> 21 <year>2005</year> 22 <price>30.00</price> 23 </book> 24 <book category="children"> 25 <!-- A popular book --> 26 <title lang="en">Harry Potter</title> 27 <author>J. K. Rowling</author> 28 <year>2005</year> 29 <price>29.99</price> 30 </book> 31</bookstore> 32XML; 33 34 // DOMDocumentオブジェクトを作成し、XMLを読み込む 35 $dom = new DOMDocument(); 36 $dom->loadXML($xmlString); 37 38 // DOMXPathオブジェクトを作成 39 $xpath = new DOMXPath($dom); 40 41 // XPathクエリを使用して、2番目の<book>要素ノードを取得する 42 // query()メソッドはDOMNodeListを返すため、最初の要素をitem(0)で取得 43 $query = '//book[2]'; 44 $bookNode = $xpath->query($query)->item(0); 45 46 // 取得したノードが存在する場合のみ処理を続行 47 if ($bookNode) { 48 // DOMEntity, DOMElementなど多くのDOMNode派生クラスが持つchildNodesプロパティを取得 49 // これには子要素、テキスト、コメントなどがすべて含まれる 50 $childNodes = $bookNode->childNodes; 51 52 echo "XPathクエリ '{$query}' で取得したノードの子ノード一覧:\n"; 53 echo "----------------------------------------\n"; 54 55 // DOMNodeListをループで処理 56 foreach ($childNodes as $child) { 57 // ノードの種類に応じて情報を出力 58 // #text は要素間の改行やインデントによる空白テキストノード 59 // #comment はコメントノード 60 // title, author などは要素ノード 61 printf( 62 "ノード名: %-10s | ノードタイプ: %-2d | ノード値: %s\n", 63 $child->nodeName, 64 $child->nodeType, 65 trim($child->nodeValue) // nodeValueから前後の空白を削除して表示 66 ); 67 } 68 } 69} 70 71// 関数を実行 72processChildNodesWithXPath();
このPHPコードは、XML文書の中からXPathを利用して特定の要素を取得し、その要素が持つすべての子ノードを一覧表示するサンプルです。
childNodesは、XMLやHTMLの特定の要素(ノード)の直下にある、すべての子ノードを取得するためのプロパティです。このプロパティは引数を取らず、戻り値として子ノードの集合であるDOMNodeListオブジェクトを返します。DOMNodeListはforeach文を使って、含まれる各ノードを順番に処理することができます。
このサンプルの重要な点は、childNodesが返すリストには、<title>のような「要素ノード」だけでなく、<!-- A popular book -->のような「コメントノード」や、要素間の改行・インデントによる空白文字からなる「テキストノード」もすべて含まれることです。
コードでは、まずXPathクエリで2番目の<book>要素を取得します。次に、その要素のchildNodesプロパティにアクセスしてDOMNodeListを取得し、ループ処理で各子ノードの種類や名前、値を出力しています。これにより、意図した要素だけでなく、空白やコメントもノードとして扱われていることが具体的に確認できます。
childNodes プロパティは、<title>のような要素ノードだけでなく、要素間の改行やインデントによる空白(テキストノード)やコメントノードもすべて取得します。このため、子要素の数だけを想定してループ処理を行うと、意図しないノードも処理してしまい、バグの原因となる点に注意が必要です。もし要素ノードだけを扱いたい場合は、ループ内で nodeType プロパティの値が XML_ELEMENT_NODE (定数値1) であるかを確認する条件分岐を追加するのが確実です。また、XPathの query メソッドの実行結果は常に DOMNodeList となり、対象が見つからない場合もあるため、item(0) でノードを取得した後に null でないかを確認する処理は、エラー防止のために不可欠です。