【PHP8.x】childNodesプロパティの使い方
childNodesプロパティの使い方について、初心者にもわかりやすく解説します。
基本的な使い方
childNodesプロパティは、所属するDom\DocumentTypeクラスのインスタンスが保持する子ノードのリストを表すプロパティです。
Dom\DocumentTypeクラスは、HTMLやXMLドキュメントの冒頭に記述されるDOCTYPE宣言(例: <!DOCTYPE html>)を表します。この宣言は、ドキュメントがどのHTMLまたはXMLの仕様に準拠しているかをブラウザやパーサーに伝えるための重要な情報です。
一般的に、childNodesプロパティは、DOMツリー内の特定のノードの直下にある全ての子ノードをDom\NodeListオブジェクトとして保持します。しかしながら、Dom\DocumentTypeのインスタンスにおいては、このchildNodesプロパティは常に空のDom\NodeListオブジェクトを返します。
これは、DOCTYPE宣言が、それ自身の内部にさらに子要素やテキストといった具体的なノード構造を持つものではないためです。DOCTYPE宣言はあくまでドキュメント全体の型情報を定義する独立した存在であり、DOMツリーの階層構造としては子ノードを持たないと解釈されます。
したがって、このプロパティはDom\DocumentTypeオブジェクトに対してアクセスされた場合、その型情報の特性上、常に空の子ノードリストを返すという挙動を示します。この点を理解しておくことで、PHP 8のDOM拡張機能を用いてドキュメントを解析する際の混乱を防ぐことができます。
構文(syntax)
1<?php 2 3// DOMDocument オブジェクトを作成します。 4$dom = new DOMDocument(); 5 6// <!DOCTYPE ...> 定義を含むHTML文字列をロードします。 7// DocumentType ノード(DOCTYPE)は通常、子ノードを持たないため、 8// childNodes プロパティは空の NodeList を返します。 9$dom->loadHTML('<!DOCTYPE html><html><body></body></html>'); 10 11// ドキュメントの DocumentType ノードを取得します。 12$documentType = $dom->doctype; 13 14// DocumentType ノードが存在する場合に処理します。 15if ($documentType instanceof Dom\DocumentType) { 16 // childNodes プロパティにアクセスし、子ノードのリストを取得します。 17 // Dom\DocumentType の場合、このリストは通常空です。 18 $childNodesList = $documentType->childNodes; 19 20 // 取得した NodeList の要素数(子ノードの数)を表示します。 21 // 通常は 0 となります。 22 echo "DocumentType の子ノード数: " . $childNodesList->length . "\n"; 23} else { 24 echo "DocumentType ノードが見つかりませんでした。\n"; 25} 26 27?>
引数(parameters)
引数なし
引数はありません
戻り値(return)
Dom\NodeList
このプロパティは、このドキュメントタイプノードの子ノードのリストを Dom\NodeList オブジェクトとして返します。
サンプルコード
PHP DOM childNodes で Doctype 子ノードを取得する
1<?php 2 3declare(strict_types=1); 4 5/** 6 * Dom\DocumentType->childNodes の使用例を示します。 7 * 8 * このプロパティは、DOCTYPE宣言の内部サブセットに含まれるノードの 9 * リスト (Dom\NodeList) を返します。 10 * 例えば、<!ENTITY ...> や <!ELEMENT ...> 宣言などが子ノードに該当します。 11 */ 12function demonstrateDocumentTypeChildNodes(): void 13{ 14 // DTD(文書型定義)の内部サブセットを持つXML文字列を定義します。 15 // `greeting` 要素と `writer` エンティティが宣言されています。 16 $xmlString = <<<XML 17 <?xml version="1.0" encoding="UTF-8"?> 18 <!DOCTYPE greeting [ 19 <!ELEMENT greeting (#PCDATA)> 20 <!ENTITY writer "World"> 21 ]> 22 <greeting>Hello, &writer;!</greeting> 23 XML; 24 25 // DOMDocumentオブジェクトを作成し、XMLを読み込みます。 26 $doc = new DOMDocument(); 27 $doc->loadXML($xmlString); 28 29 // DOMDocumentからDocumentTypeノードを取得します。 30 // これは `<!DOCTYPE ...>` 全体を表すオブジェクトです。 31 $docType = $doc->doctype; 32 33 // DocumentTypeノードが存在するか確認します。 34 if ($docType === null) { 35 echo 'DOCTYPEノードが見つかりませんでした。' . PHP_EOL; 36 return; 37 } 38 39 echo 'DOCTYPE名: ' . $docType->name . PHP_EOL; 40 echo '--- DocumentTypeの子ノードリスト ---' . PHP_EOL; 41 42 // childNodesプロパティにアクセスして、子ノードのリストを取得します。 43 $childNodes = $docType->childNodes; 44 45 if ($childNodes->length > 0) { 46 // NodeListをループ処理し、各子ノードの情報を出力します。 47 foreach ($childNodes as $index => $node) { 48 // $node は Dom\Node を継承したオブジェクトです (この例では Dom\Entity や Dom\ElementDeclaration)。 49 printf( 50 "[%d] ノード名: %s, ノードタイプ: %d\n", 51 $index, 52 $node->nodeName, // ELEMENT宣言なら要素名、ENTITY宣言ならエンティティ名 53 $node->nodeType // ノードの種類を表す定数 (例: DOM_ELEMENT_NODE, DOM_ENTITY_NODE) 54 ); 55 } 56 } else { 57 echo '子ノードはありません。' . PHP_EOL; 58 } 59} 60 61// 関数を実行して結果を表示します。 62demonstrateDocumentTypeChildNodes(); 63 64?>
Dom\DocumentTypeのchildNodesプロパティは、XML文書のDOCTYPE宣言の内部サブセットに含まれる、すべての子ノードのリストを取得するために使用します。内部サブセットとは、<!DOCTYPE ... [...]>の角括弧内に記述される宣言部分のことです。このプロパティは引数を必要としません。
サンプルコードでは、まず<!ELEMENT>(要素型宣言)と<!ENTITY>(実体宣言)を含むXML文字列を定義しています。次に、DOMDocumentクラスでこのXMLを読み込み、doctypeプロパティからDom\DocumentTypeオブジェクトを取得します。
続いて$docType->childNodesにアクセスすることで、DOCTYPE宣言の内部サブセットに含まれる子ノードのリストをDom\NodeListオブジェクトとして取得します。このDom\NodeListは、この例では<!ELEMENT greeting ...>と<!ENTITY writer ...>に対応するノードを格納したコレクションです。
最後に、取得したNodeListをforeachでループ処理し、各ノードの名前と種類を出力しています。これにより、DOCTYPE宣言内にどのような定義が含まれているかをプログラムで確認できます。子ノードが存在しない場合、NodeListは空になります。
このプロパティは、XMLの主要なデータ要素ではなく、文書型定義(DTD)の内部にある宣言(<!ELEMENT>や<!ENTITY>など)のリストを返します。初心者が混同しやすい点なので注意してください。また、XML文書にDOCTYPE宣言が含まれていない場合、$doc->doctypeはnullになります。そのため、childNodesプロパティにアクセスする前には、必ずnullでないことを確認する処理が必要です。これを怠るとエラーが発生します。取得したDom\NodeListはforeachで扱えますが、リスト内の各ノードは種類が異なるため、nodeTypeプロパティで型を確認しながら処理するのが安全です。
PHP: DOCTYPEの子ノードを取得する
1<?php 2 3declare(strict_types=1); 4 5/** 6 * XMLドキュメントのDOCTYPE宣言から子ノードを取得するサンプルコード 7 * 8 * Dom\DocumentTypeクラスのchildNodesプロパティを使用して、 9 * DTD(文書型定義)内に宣言されたエンティティなどの子ノードを一覧表示します。 10 * XPathはDOMツリーの操作という広い文脈で関連しますが、この例では 11 * より直接的なプロパティアクセスに焦点を当てています。 12 */ 13function displayDocumentTypeChildNodes(): void 14{ 15 // DOCTYPE宣言と内部サブセット(エンティティ宣言)を含むXML文字列 16 $xmlString = <<<XML 17<?xml version="1.0" encoding="UTF-8"?> 18<!DOCTYPE bookstore [ 19 <!ENTITY author "J.K. Rowling"> 20 <!ENTITY publisher "Bloomsbury"> 21]> 22<bookstore> 23 <book category="fantasy"> 24 <title lang="en">Harry Potter</title> 25 <author>&author;</author> 26 <year>2005</year> 27 <price>29.99</price> 28 </book> 29</bookstore> 30XML; 31 32 // DOMDocumentオブジェクトをインスタンス化 33 $dom = new DOMDocument(); 34 35 // XML文字列を読み込み、パースする 36 if (!$dom->loadXML($xmlString)) { 37 echo "XMLの読み込みに失敗しました。" . PHP_EOL; 38 return; 39 } 40 41 // DocumentTypeノードを取得する (DOMDocument::$doctype プロパティ) 42 // このプロパティは Dom\DocumentType オブジェクトまたは null を返す 43 $docType = $dom->doctype; 44 45 if ($docType instanceof DOMDocumentType) { 46 echo "DOCTYPE名: " . $docType->name . PHP_EOL; 47 echo "-------------------------" . PHP_EOL; 48 49 // childNodesプロパティにアクセスし、子ノードのリスト(Dom\NodeList)を取得 50 $childNodes = $docType->childNodes; 51 52 if ($childNodes->length > 0) { 53 echo "DOCTYPE宣言の子ノード一覧:" . PHP_EOL; 54 // NodeListをループして各子ノードの情報を出力 55 foreach ($childNodes as $node) { 56 // ノードの種類がエンティティ宣言(DOMEntity)であるかを確認 57 if ($node instanceof DOMEntity) { 58 // ノード名(エンティティ名)を出力 59 echo " - " . $node->nodeName . " (型: " . get_class($node) . ")" . PHP_EOL; 60 } 61 } 62 } else { 63 echo "DOCTYPE宣言に子ノードは見つかりませんでした。" . PHP_EOL; 64 } 65 } else { 66 echo "DOCTYPE宣言が見つかりませんでした。" . PHP_EOL; 67 } 68} 69 70// 関数を実行 71displayDocumentTypeChildNodes(); 72
このPHPサンプルコードは、XML文書のDOCTYPE宣言に含まれる子ノードの情報を取得する方法を示します。ここで中心となるのがDom\DocumentTypeクラスのchildNodesプロパティです。このプロパティは引数を取らず、DOCTYPE宣言の直下にあるすべての子ノードを、リスト形式のDom\NodeListオブジェクトとして返します。
コードの処理の流れは次の通りです。まず、内部にエンティティ宣言(<!ENTITY>)を持つXML文字列をDOMDocumentクラスで読み込みます。次に、$dom->doctypeプロパティを使って文書全体のDOCTYPE宣言を表すDom\DocumentTypeオブジェクトを取得します。そして、そのオブジェクトのchildNodesプロパティにアクセスすることで、子ノードのリストを取得します。最後にforeachループでリスト内の各ノードを順に確認し、ノードがエンティティ(DOMEntity)であれば、その名前(nodeName)を出力しています。このようにして、XMLの文書型定義(DTD)内に含まれる情報をプログラムで直接取得・操作できます。
XMLドキュメントにDOCTYPE宣言が存在しない場合、$dom->doctypeプロパティはnullを返します。そのため、サンプルコードのようにchildNodesへアクセスする前に、必ずnullでないかを確認する処理が必要です。この確認を怠るとエラーの原因となります。また、childNodesプロパティが返すノードリストには、エンティティ宣言だけでなくコメントなど他の種類のノードも含まれる可能性があります。ループ処理を行う際は、instanceofを用いてノードの型を判定し、意図した型のノードのみを処理するようにしてください。これにより、想定外のデータが処理されることを防ぎ、より安全なコードになります。