【PHP8.x】Dom\Notation::childNodesプロパティの使い方
childNodesプロパティの使い方について、初心者にもわかりやすく解説します。
基本的な使い方
childNodesプロパティは、DOMツリーにおける現在のノードの直接の子ノードのリストを保持するプロパティです。このプロパティにアクセスすると、すべての子ノードを格納したDOMNodeListオブジェクトが返されます。しかし、Dom\Notationクラスのインスタンスにこのプロパティが適用される場合、その振る舞いは通常の要素ノードとは異なります。
Dom\Notationクラスは、XMLドキュメントのDTD(Document Type Definition)内で定義される「表記(NOTATION)」を表します。表記は、XML外部の非XMLデータを識別するために使用され、通常は画像ファイルや特定のアプリケーションで処理されるべきデータ型などを指定する際に利用されます。このDom\Notationノード自体は、他のXML要素やテキストノードのような子ノードを持つ構造ではありません。
したがって、Dom\NotationオブジェクトのchildNodesプロパティにアクセスしても、常に空のDOMNodeListオブジェクトが返されます。このプロパティを使って子ノードを走査しようとしても、何も得られないことを意味します。プログラミングを行う際には、各DOMノードのタイプが持つ特性と、それに伴うプロパティの具体的な動作を理解することが、適切な処理を実装する上で非常に重要です。特に、Dom\Notationのような特殊なノードでは、その特性を把握しておく必要があります。
構文(syntax)
1<?php 2$xml = <<<XML 3<!DOCTYPE root [ 4 <!NOTATION gif SYSTEM "image/gif"> 5 <!ELEMENT root EMPTY> 6]> 7<root/> 8XML; 9 10$dom = new DOMDocument(); 11$dom->loadXML($xml); 12 13$notation = null; 14if ($dom->doctype && $dom->doctype->notations->length > 0) { 15 $notation = $dom->doctype->notations->item(0); 16} 17 18if ($notation) { 19 $childNodes = $notation->childNodes; 20}
引数(parameters)
引数なし
引数はありません
戻り値(return)
Dom\NodeList
Dom\NodeListオブジェクトを返します。これは、この要素のすべての子ノードを保持するリストです。
サンプルコード
PHP DOM childNodes で Notation の子ノードを確認する
1<?php 2 3/** 4 * Dom\Notation オブジェクトの childNodes プロパティの使用例を示します。 5 * 6 * Notation ノードは子ノードを持つことができないため、 7 * childNodes プロパティは常に空の NodeList を返します。 8 * このコードは、その動作を確認します。 9 */ 10function demonstrateNotationChildNodes(): void 11{ 12 // DTD内でNotationを定義したXML文字列を作成 13 $xmlString = <<<XML 14 <?xml version="1.0" encoding="UTF-8"?> 15 <!DOCTYPE doc [ 16 <!NOTATION jpeg SYSTEM "image/jpeg"> 17 ]> 18 <doc></doc> 19 XML; 20 21 // DOMDocumentオブジェクトを作成し、XMLを読み込む 22 // PHP 8では `new Dom\Document()` と同義です 23 $dom = new DOMDocument(); 24 $dom->loadXML($xmlString); 25 26 // DocumentTypeノード(<!DOCTYPE ...>)を取得 27 // NotationはDocumentTypeノードに属します 28 $doctype = $dom->doctype; 29 30 if ($doctype === null) { 31 echo 'DocumentTypeノードが見つかりませんでした。' . PHP_EOL; 32 return; 33 } 34 35 // "jpeg"という名前のNotationノードを取得 36 // $doctype->notations は Dom\NamedNodeMap を返します 37 /** @var Dom\Notation|null $notation */ 38 $notation = $doctype->notations?->getNamedItem('jpeg'); 39 40 if ($notation) { 41 // NotationノードのchildNodesプロパティにアクセス 42 // このプロパティは Dom\NodeList を返します 43 $childNodes = $notation->childNodes; 44 45 // Notationノードは子を持つことができないため、lengthは常に0になります 46 echo 'Notationノード名: ' . $notation->nodeName . PHP_EOL; 47 echo '子ノードの数: ' . $childNodes->length . PHP_EOL; // "0" が出力される 48 49 if ($childNodes->length === 0) { 50 echo '--> 結果: Dom\\Notation は子ノードを持たないことが確認できました。' . PHP_EOL; 51 } 52 } else { 53 echo '指定されたNotationノードが見つかりませんでした。' . PHP_EOL; 54 } 55} 56 57// 関数を実行して結果を表示 58demonstrateNotationChildNodes(); 59
このPHPサンプルコードは、DOM拡張機能におけるDom\NotationオブジェクトのchildNodesプロパティの挙動を解説します。childNodesプロパティは、あるノードの直下にある子ノードのリストを取得するためのものです。このプロパティに引数はなく、戻り値としてノードの集合を表すDom\NodeListオブジェクトを返します。
Dom\Notationは、XMLのDTD(文書型定義)内で、画像形式のような外部の非XMLデータの表記法を定義するために使われる特殊なノードです。XMLの仕様上、Notationノードは子要素やテキストといった子ノードを持つことができません。
このコードでは、まずDTD内にjpegというNotationを定義したXML文字列を準備し、DOMDocumentオブジェクトで読み込みます。次に、文書の型定義(doctype)からjpegという名前のNotationノードを取得し、そのchildNodesプロパティにアクセスしています。
実行結果として、取得したDom\NodeListのlengthプロパティ(ノードの数)が常に0であることが示されます。これにより、Dom\Notationは子ノードを持たないという仕様をプログラム上で明確に確認することができます。
Dom\NotationクラスのchildNodesプロパティは、仕様上、常に子ノードを持たないため、空のリスト(Dom\NodeList)を返します。したがって、このプロパティのlengthは常に0になります。Notationノードは、一般的なXML要素とは異なり、文書のDTD(文書型定義)内で定義される点に注意してください。取得する際は、DOMDocumentオブジェクトのdoctypeプロパティ、さらにその中のnotationsプロパティを経由してアクセスする必要があります。コード中の?->という記法はNullsafe演算子です。これはdoctypeなどが存在しない場合にエラーを出さず、安全に処理を続けるためのPHP 8の便利な機能です。
PHP: XPathで要素の子ノードを取得する
1<?php 2 3declare(strict_types=1); 4 5/** 6 * 指定されたXPathクエリに一致するXML要素を見つけ、その子ノードを一覧表示します。 7 * 8 * この関数は、DOMDocumentとDOMXPathを使用してXMLデータを解析し、 9 * 特定のノードの `childNodes` プロパティを使って子ノードリストを取得する方法を示します。 10 */ 11function displayChildNodesUsingXPath(): void 12{ 13 // サンプルとして使用するXML文字列 14 $xmlString = <<<XML 15 <?xml version="1.0" encoding="UTF-8"?> 16 <bookstore> 17 <book category="COOKING"> 18 <title lang="en">Everyday Italian</title> 19 <author>Giada De Laurentiis</author> 20 <year>2005</year> 21 </book> 22 <book category="WEB"> 23 <title lang="en">Learning XML</title> 24 <author>Erik T. Ray</author> 25 <year>2003</year> 26 </book> 27 </bookstore> 28 XML; 29 30 // 1. DOMDocumentオブジェクトを作成し、XMLを読み込む 31 $dom = new DOMDocument(); 32 $dom->loadXML($xmlString); 33 34 // 2. DOMXPathオブジェクトを作成 35 $xpath = new DOMXPath($dom); 36 37 // 3. XPathクエリで最初の <book> 要素を取得する 38 $query = '//book[1]'; 39 $nodes = $xpath->query($query); 40 41 // 4. クエリに一致するノードが存在するか確認 42 if ($nodes->length > 0) { 43 // 最初の要素ノードを取得 44 $firstBook = $nodes->item(0); 45 46 echo "XPath '{$query}' で見つかった要素 <{$firstBook->nodeName}> の子ノード一覧:\n"; 47 48 // 5. childNodes プロパティで子ノードのリスト (DOMNodeList) を取得 49 $childNodes = $firstBook->childNodes; 50 51 // 6. 子ノードをループ処理 52 foreach ($childNodes as $child) { 53 // 要素ノード (XML_ELEMENT_NODE) のみを出力対象とする 54 // (要素間の改行や空白はテキストノードとして扱われるため) 55 if ($child->nodeType === XML_ELEMENT_NODE) { 56 printf( 57 " - NodeName: %s, Content: %s\n", 58 $child->nodeName, 59 trim($child->textContent) 60 ); 61 } 62 } 63 } else { 64 echo "XPath '{$query}' に一致するノードが見つかりませんでした。\n"; 65 } 66} 67 68// 関数を実行して結果を表示 69displayChildNodesUsingXPath(); 70
childNodesは、XML文書内の特定のノードが持つ、すべての子ノードのリストを取得するためのプロパティです。このプロパティに引数はなく、戻り値としてDom\NodeListオブジェクトを返します。このオブジェクトは、子ノードの集合を格納するコレクションのようなものです。
サンプルコードでは、まずXMLデータを読み込み、XPathという検索機能を使って最初の<book>要素を特定します。次に、その見つかった<book>要素のchildNodesプロパティにアクセスすることで、その直下にあるすべての子ノード(<title>、<author>、<year>など)のリストを取得しています。取得したDom\NodeListはforeachループを使って、含まれるノードを一つずつ処理することができます。
注意点として、子ノードには<title>のような要素だけでなく、要素間の改行や空白文字などもテキストノードとして含まれる場合があります。そのため、サンプルコードではnodeTypeプロパティをチェックし、目的の要素ノード(XML_ELEMENT_NODE)のみを絞り込んで情報を出力しています。このようにchildNodesは、ある要素の直接の子をすべて取得する際に便利なプロパティです。
childNodes プロパティは、指定した要素の子要素だけでなく、要素間の改行やインデント用の空白文字からなる「テキストノード」もすべて取得します。そのため、予期せぬ動作を防ぐには、サンプルコードのように nodeType を用いて、処理したいノードの種類(例: XML_ELEMENT_NODE)を判定することが非常に重要です。また、XPathクエリに一致する要素が存在しない場合もあるため、$nodes->length で結果の件数を確認してからノードにアクセスする習慣をつけると、エラーのない安全なコードになります。この DOMNodeList は配列ではありませんが、foreach を使って簡単に各ノードを処理できます。