Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【PHP8.x】DOMDocumentType::childNodesプロパティの使い方

childNodesプロパティの使い方について、初心者にもわかりやすく解説します。

作成日: 更新日:

基本的な使い方

childNodesプロパティは、あるノードが持つすべての子ノードの集合を保持するプロパティです。このプロパティはDOMDocumentTypeクラスに属しており、XMLやHTML文書における文書型定義(DTD)を表すノードで利用されます。しかし、DOMDocumentTypeノードは、その定義上、子ノードを持つことができないという重要な特性があります。例えば、<!DOCTYPE html>のような文書型宣言は、それ自体が他の要素を内包する構造ではないためです。したがって、DOMDocumentTypeオブジェクトのchildNodesプロパティにアクセスした場合、常に空のDOMNodeListオブジェクトが返されます。この返されたDOMNodeListオブジェクトのlengthプロパティ(要素数)は常に0となります。このプロパティは読み取り専用のため、内容を直接変更することはできません。DOMツリーの階層構造を操作する際に汎用的に提供されているプロパティですが、DOMDocumentTypeにおいては子ノードが存在しないことを示すものとして機能します。

構文(syntax)

1<?php
2
3$xmlString = <<<XML
4<?xml version="1.0" encoding="UTF-8"?>
5<!DOCTYPE greeting [
6    <!ENTITY author "World">
7    <!NOTATION type-jpeg PUBLIC "image/jpeg">
8]>
9<message>Hello, &author;!</message>
10XML;
11
12$dom = new DOMDocument();
13$dom->loadXML($xmlString);
14
15$doctype = $dom->doctype;
16
17// DOMDocumentTypeのchildNodesプロパティにアクセスします。
18// これにはDTD内のノード(エンティティ、ノーテーションなど)のリストが含まれます。
19$nodeList = $doctype->childNodes;
20
21foreach ($nodeList as $child) {
22    echo $child->nodeName . PHP_EOL;
23}
24
25?>

引数(parameters)

引数なし

引数はありません

戻り値(return)

DOMNodeList

DOMDocumentType オブジェクトの子ノードのリストを DOMNodeList オブジェクトとして返します。

サンプルコード

PHP DOM childNodes でDOCTYPEノードを取得する

1<?php
2
3/**
4 * DOMDocumentTypeオブジェクトからchildNodesプロパティを取得し、その内容を表示する関数。
5 *
6 * DOMDocumentType::childNodesプロパティは、DOCTYPE宣言内のエンティティ宣言や記法宣言などを
7 * DOMNodeListとして返します。一般的なHTML5のDOCTYPEでは通常空になりますが、
8 * この例ではDTD内部サブセットを持つXMLを使用し、childNodesに要素が含まれることを示します。
9 */
10function demonstrateDomDocumentTypeChildNodes(): void
11{
12    // 内部DTDサブセットを含むXML文字列を定義します。
13    // このDOCTYPE宣言には、"my_entity" というエンティティ宣言と "gif" という記法宣言が含まれています。
14    $xmlString = <<<XML
15<?xml version="1.0" encoding="UTF-8"?>
16<!DOCTYPE root [
17  <!ENTITY my_entity "このテキストはエンティティです。">
18  <!NOTATION gif SYSTEM "image/gif">
19]>
20<root>
21  <element>&my_entity;</element>
22</root>
23XML;
24
25    $dom = new DOMDocument('1.0', 'UTF-8');
26    // XML文字列をDOMDocumentオブジェクトにロードします。
27    // ロードが成功したかを確認します。
28    if (!$dom->loadXML($xmlString)) {
29        echo "XMLのロードに失敗しました。\n";
30        return;
31    }
32
33    // DOMDocumentオブジェクトからDOCTYPEノードを取得します。
34    // `doctype`プロパティはDOMDocumentTypeオブジェクトを返します。
35    $doctype = $dom->doctype;
36
37    if ($doctype instanceof DOMDocumentType) {
38        echo "--- DOMDocumentType::childNodesのデモンストレーション ---\n";
39        echo "DOCTYPE名: " . $doctype->name . "\n";
40        echo "システムID: " . ($doctype->systemId ?: "なし") . "\n"; // 外部DTDの場所を示すURI (この例では内部DTDなのでなし)
41        echo "公開ID: " . ($doctype->publicId ?: "なし") . "\n";   // 公開識別子 (この例では内部DTDなのでなし)
42
43        // childNodesプロパティにアクセスします。
44        // これはDOCTYPE宣言内で定義されたノードのリスト (DOMNodeList) を返します。
45        $childNodes = $doctype->childNodes;
46
47        echo "\nDOCTYPEの内部サブセットに定義された子ノード数: " . $childNodes->length . "\n";
48
49        if ($childNodes->length > 0) {
50            echo "--- 各子ノードの詳細 ---\n";
51            foreach ($childNodes as $index => $node) {
52                echo "ノード " . ($index + 1) . ":\n";
53                echo "  ノード名: " . $node->nodeName . "\n";
54                echo "  ノードタイプ: " . $node->nodeType . " (" . getNodeTypeName($node->nodeType) . ")\n";
55
56                // DOMEntityノードの場合、その値(エンティティの内容)を表示
57                if ($node instanceof DOMEntity) {
58                    echo "  エンティティ値: " . $node->nodeValue . "\n";
59                }
60                // DOMNotationノードの場合、その属性(システムIDや公開ID)を表示
61                if ($node instanceof DOMNotation) {
62                    echo "  記法システムID: " . ($node->systemId ?: "なし") . "\n";
63                    echo "  記法公開ID: " . ($node->publicId ?: "なし") . "\n";
64                }
65                echo "\n";
66            }
67        } else {
68            echo "DOCTYPEの内部サブセットに子ノードは定義されていません。\n";
69        }
70    } else {
71        echo "文書にDOCTYPE宣言が見つかりませんでした。\n";
72    }
73}
74
75/**
76 * ノードタイプを示す定数値を人間に読みやすい文字列に変換するヘルパー関数。
77 * (DOMNodeの定数を使用)
78 *
79 * @param int $type DOMNode::NODE_TYPE_* のいずれかの値
80 * @return string ノードタイプを示す文字列
81 */
82function getNodeTypeName(int $type): string
83{
84    return match ($type) {
85        XML_ELEMENT_NODE       => 'ELEMENT_NODE',
86        XML_ATTRIBUTE_NODE     => 'ATTRIBUTE_NODE',
87        XML_TEXT_NODE          => 'TEXT_NODE',
88        XML_CDATA_SECTION_NODE => 'CDATA_SECTION_NODE',
89        XML_ENTITY_REF_NODE    => 'ENTITY_REF_NODE',
90        XML_ENTITY_NODE        => 'ENTITY_NODE', // DOMDocumentType::childNodesが返すノード
91        XML_PI_NODE            => 'PROCESSING_INSTRUCTION_NODE',
92        XML_COMMENT_NODE       => 'COMMENT_NODE',
93        XML_DOCUMENT_NODE      => 'DOCUMENT_NODE',
94        XML_DOCUMENT_TYPE_NODE => 'DOCUMENT_TYPE_NODE',
95        XML_DOCUMENT_FRAG_NODE => 'DOCUMENT_FRAGMENT_NODE',
96        XML_NOTATION_NODE      => 'NOTATION_NODE', // DOMDocumentType::childNodesが返すノード
97        XML_HTML_DOCUMENT_NODE => 'HTML_DOCUMENT_NODE',
98        default                => 'UNKNOWN_NODE_TYPE',
99    };
100}
101
102// 関数の実行
103demonstrateDomDocumentTypeChildNodes();

DOMDocumentType::childNodesは、PHPのDOM拡張機能において、XML文書のDOCTYPE(文書型定義)宣言内に記述された内部サブセットの情報を取得するためのプロパティです。このプロパティは引数を取らず、戻り値としてDOMNodeListオブジェクトを返します。DOMNodeListには、DOCTYPE宣言内で定義されたエンティティ宣言(DOMEntityノード)や記法宣言(DOMNotationノード)などが含まれます。

一般的なHTML5のDOCTYPEでは内部サブセットがないため、通常childNodesは空のリストを返しますが、サンプルコードでは内部DTDサブセットを持つXMLを例に、childNodesが実際に情報を保持するケースを示しています。コードではまず、エンティティ宣言と記法宣言を含むXML文字列を定義し、それをDOMDocumentオブジェクトにロードします。次に、$dom->doctypeプロパティを通じてDOMDocumentTypeオブジェクトを取得し、そのchildNodesプロパティにアクセスしています。

取得したDOMNodeListはループ処理によって個々の子ノードにアクセスでき、それぞれのノード名、ノードタイプ、そしてDOMEntityの場合はエンティティ値、DOMNotationの場合はシステムIDや公開IDといった具体的な詳細情報を表示しています。このように、DOMDocumentType::childNodesを利用することで、DOCTYPE宣言の内部構造をプログラムから詳細に調べ、操作することが可能になります。

DOMDocumentType::childNodesプロパティは、DOCTYPE宣言内の内部サブセットで定義されたエンティティ宣言や記法宣言などのノードを取得します。一般的なHTML5のDOCTYPE宣言(例: <!DOCTYPE html>)では通常子ノードは含まれず、返されるDOMNodeListは空になるため注意が必要です。このサンプルコードは、DTDの内部サブセットを持つXMLを使用して、子ノードが存在する場合の動作を示しています。取得されるノードはDOMEntityDOMNotationといった特定の型の場合があるため、ループ内でinstanceofを使って型を判別すると安全に処理できます。XMLの読み込みに失敗していないか、また$dom->doctypeDOMDocumentTypeオブジェクトとして正しく取得されているかを必ず確認してからプロパティにアクセスしてください。

PHP DOMDocumentType::childNodes を取得する

1<?php
2
3/**
4 * DOMDocumentType クラスの childNodes プロパティの使用方法を示す関数。
5 * システムエンジニアを目指す初心者が、DOM ツリーで DOCTYPE の子ノードにアクセスする方法を理解するのに役立ちます。
6 */
7function demonstrateDomDocumentTypeChildNodes(): void
8{
9    // DOMDocument の新しいインスタンスを作成します。
10    // これは XML または HTML ドキュメント全体を表すメインのオブジェクトです。
11    $dom = new DOMDocument();
12
13    // HTML ドキュメントを文字列からロードします。
14    // <!DOCTYPE html> 宣言が含まれているため、DOMDocumentType オブジェクトが生成されます。
15    // loadHTML は HTML5 の DOCTYPE も適切に処理します。
16    $html = '<!DOCTYPE html>
17             <html>
18             <head>
19                 <title>PHP DOM DocumentType Example</title>
20             </head>
21             <body>
22                 <h1>Welcome to DOMDocumentType</h1>
23                 <p>This document demonstrates accessing the DOCTYPE node\'s childNodes.</p>
24             </body>
25             </html>';
26    $dom->loadHTML($html);
27
28    // ドキュメントの DOMDocumentType オブジェクトを取得します。
29    // これはドキュメントタイプ宣言 (例: <!DOCTYPE html>) を表すノードです。
30    $doctype = $dom->doctype;
31
32    // DOMDocumentType オブジェクトが正常に取得できたか確認します。
33    if ($doctype instanceof DOMDocumentType) {
34        echo "DOCTYPE が見つかりました。\n";
35        echo "  名前 (name): " . $doctype->name . "\n"; // DOCTYPE の名前 (例: html)
36        echo "  Public ID: " . ($doctype->publicId ?: "なし") . "\n"; // パブリック識別子
37        echo "  System ID: " . ($doctype->systemId ?: "なし") . "\n"; // システム識別子
38
39        // DOMDocumentType の子ノード (childNodes) を取得します。
40        // childNodes は DOMNodeList を返します。
41        // 通常の HTML5 の <!DOCTYPE html> 宣言では、DOMDocumentType ノード自体は直接的な子ノードを持ちません。
42        // 子ノードは、DTD の内部サブセット(エンティティや表記法など)がある場合にのみ存在します。
43        $childNodes = $doctype->childNodes;
44
45        echo "\nDOMDocumentType の子ノードの数: " . $childNodes->length . "\n";
46
47        // 子ノードが存在する場合、それぞれの情報を出力します。
48        if ($childNodes->length > 0) {
49            echo "子ノード:\n";
50            foreach ($childNodes as $node) {
51                // 各子ノードの名前とタイプを出力します。
52                echo "  - ノード名: " . $node->nodeName . ", ノードタイプ: " . $node->nodeType . " (" . get_class($node) . ")\n";
53            }
54        } else {
55            // HTML5 のようなシンプルな DOCTYPE では、通常、子ノードは存在しないことを説明します。
56            echo "  注意: HTML5 ドキュメントの DOCTYPE は、通常、直接的な子ノードを持ちません。\n";
57            echo "  子ノードは、DTD の内部サブセット(エンティティや表記法の定義など)が存在する場合にのみ表示されます。\n";
58        }
59    } else {
60        echo "このドキュメントには DOCTYPE が見つかりませんでした。\n";
61    }
62}
63
64// 上記の関数を実行して、DOMDocumentType::childNodes の動作をデモンストレーションします。
65demonstrateDomDocumentTypeChildNodes();
66
67?>

DOMDocumentType::childNodesプロパティは、HTMLやXMLドキュメントのDOCTYPE宣言(例: <!DOCTYPE html>)を表すDOMDocumentTypeオブジェクトの子ノードのリストを取得するために使用されます。

このプロパティは引数を取らず、戻り値としてDOMNodeListオブジェクトを返します。DOMNodeListは、取得された子ノードを順番に含むコレクションです。

サンプルコードでは、DOMDocumentにHTML文字列をロードし、そこからdoctypeプロパティを使ってDOMDocumentTypeオブジェクトを取得しています。その後、取得した$doctypeオブジェクトのchildNodesプロパティにアクセスし、子ノードの数を確認しています。

しかし、一般的なHTML5ドキュメントの<!DOCTYPE html>のようなシンプルなDOCTYPE宣言には、通常、直接的な子ノードは存在しません。childNodesにノードが含まれるのは、DTD(Document Type Definition)にエンティティや表記法などの内部サブセットが定義されている特殊なケースに限られます。

そのため、サンプルコードの実行結果では、通常「子ノードの数: 0」と表示され、「HTML5ドキュメントのDOCTYPEは、通常、直接的な子ノードを持ちません」という注意書きが表示されることを確認できます。これは、DOMDocumentTypeオブジェクトが、DTDの内部構造を表す際に利用されるプロパティであることを示しています。

DOMDocumentType::childNodesプロパティは、DOCTYPE宣言の子ノードをDOMNodeListとして返します。しかし、一般的なHTML5の<!DOCTYPE html>のようなDOCTYPE宣言では、通常、子ノードは存在しません。子ノードが見つからない場合はエラーではなく、仕様通りの動作ですのでご注意ください。子ノードは、DTD(文書型定義)内にエンティティや表記法の定義など、内部サブセットが存在する場合にのみ取得できます。また、$dom->doctypeでDOMDocumentTypeオブジェクトが取得できない場合もありますので、instanceofでその存在を必ず確認してからchildNodesプロパティにアクセスしてください。

PHP DOM childNodesとXPathで要素子ノードを取得する

1<?php
2
3/**
4 * DOMDocumentTypeのchildNodesプロパティと、XPathを使用した要素のchildNodesの取得を実演します。
5 * システムエンジニアを目指す初心者が、DOMのノード構造とXPathの基本的な使い方を理解するのに役立ちます。
6 */
7function demonstrateDomChildNodes(): void
8{
9    // サンプルとなるHTML文字列を定義します。
10    // <!DOCTYPE html>宣言と、いくつかの要素が含まれています。
11    $htmlString = <<<HTML
12<!DOCTYPE html>
13<html>
14<head>
15    <title>サンプルページ</title>
16</head>
17<body>
18    <h1>こんにちは、DOMの世界へ!</h1>
19    <p>これは段落です。</p>
20    <!-- コメントノード -->
21</body>
22</html>
23HTML;
24
25    // DOMDocumentオブジェクトを作成し、HTMLを読み込みます。
26    // LIBXML_HTML_NOIMPLIED と LIBXML_HTML_NODEFDTD は、DOMDocumentが自動的に追加するDOCTYPEや<html><body>タグを抑制し、
27    // ソースHTMLの構造をより忠実に保つためのオプションですが、ここではloadHTMLが自動的にDOCTYPEを認識します。
28    $dom = new DOMDocument();
29    // HTMLを読み込む際のエラーを抑制します。
30    @$dom->loadHTML($htmlString);
31
32    echo "--- DOMDocumentTypeの childNodes プロパティ ---\n";
33
34    // ドキュメントタイプノード(<!DOCTYPE html>)を取得します。
35    $documentType = $dom->doctype;
36
37    if ($documentType instanceof DOMDocumentType) {
38        echo "DOMDocumentTypeが見つかりました: " . $documentType->name . "\n";
39        echo "DOMDocumentTypeのsystemId: " . ($documentType->systemId ?: 'なし') . "\n";
40        echo "DOMDocumentTypeのpublicId: " . ($documentType->publicId ?: 'なし') . "\n";
41
42        // DOMDocumentTypeのchildNodesプロパティはDOMNodeListを返しますが、
43        // 通常のHTMLではDOMDocumentType自体に直接の子ノードは存在しないか、非常に特殊な場合のみです。
44        // (例:DTDの内部サブセットにエンティティ宣言などがある場合)
45        $dtChildNodes = $documentType->childNodes;
46
47        if ($dtChildNodes->length > 0) {
48            echo "DOMDocumentTypeの直接の子ノード:\n";
49            foreach ($dtChildNodes as $node) {
50                echo "  - ノード名: " . $node->nodeName . ", ノードタイプ: " . $node->nodeType . "\n";
51            }
52        } else {
53            echo "この例では、DOMDocumentTypeには直接の子ノードはありません。\n";
54        }
55    } else {
56        echo "DOMDocumentTypeが見つかりませんでした。\n";
57    }
58
59    echo "\n--- XPathを使った要素の childNodes 取得 ---\n";
60
61    // DOMXPathオブジェクトを作成し、ドキュメントに対してXPathクエリを実行できるようにします。
62    $xpath = new DOMXPath($dom);
63
64    // XPathクエリ '//h1' を使用して、ドキュメント内のすべての<h1>要素を検索します。
65    $h1Elements = $xpath->query('//h1');
66
67    if ($h1Elements->length > 0) {
68        // 最初の<h1>要素を取得します。
69        $h1Element = $h1Elements->item(0);
70
71        if ($h1Element instanceof DOMElement) {
72            echo "XPathで<h1>要素が見つかりました: <" . $h1Element->nodeName . ">\n";
73
74            // <h1>要素のchildNodesプロパティにアクセスします。
75            // これにより、<h1>タグ内のすべての直接の子ノード(テキストノードなど)が取得されます。
76            $h1ChildNodes = $h1Element->childNodes;
77
78            if ($h1ChildNodes->length > 0) {
79                echo "<h1>要素の直接の子ノード:\n";
80                foreach ($h1ChildNodes as $node) {
81                    echo "  - ノード名: " . $node->nodeName;
82                    // ノードタイプがテキストノードの場合、その内容も表示します。
83                    if ($node->nodeType === XML_TEXT_NODE) {
84                        echo " (内容: '" . trim($node->nodeValue) . "')";
85                    }
86                    echo "\n";
87                }
88            } else {
89                echo "<h1>要素には直接の子ノードがありませんでした。\n";
90            }
91        }
92    } else {
93        echo "XPathで<h1>要素が見つかりませんでした。\n";
94    }
95
96    echo "\n--- XPathを使った他の要素の childNodes 取得 (例: body) ---\n";
97    $bodyElements = $xpath->query('//body');
98    if ($bodyElements->length > 0) {
99        $bodyElement = $bodyElements->item(0);
100        if ($bodyElement instanceof DOMElement) {
101            echo "XPathで<body>要素が見つかりました: <" . $bodyElement->nodeName . ">\n";
102            echo "<body>要素の直接の子ノード:\n";
103            foreach ($bodyElement->childNodes as $node) {
104                // DOMNode::nodeName は要素名、DOMNode::nodeValue はテキスト内容やコメント内容などを返します。
105                // テキストノード (#text) やコメントノード (#comment) も子ノードとしてカウントされます。
106                echo "  - ノード名: " . $node->nodeName;
107                if ($node->nodeType === XML_TEXT_NODE) {
108                    $trimmedValue = trim($node->nodeValue);
109                    if ($trimmedValue !== '') {
110                        echo " (テキスト: '" . $trimmedValue . "')";
111                    }
112                } elseif ($node->nodeType === XML_COMMENT_NODE) {
113                    echo " (コメント: '" . trim($node->nodeValue) . "')";
114                }
115                echo "\n";
116            }
117        }
118    } else {
119        echo "XPathで<body>要素が見つかりませんでした。\n";
120    }
121}
122
123// 関数を実行します。
124demonstrateDomChildNodes();

PHPのDOMDocumentTypeクラスに属するchildNodesプロパティは、ドキュメントタイプノード(<!DOCTYPE html>など)の直接の子ノードを取得します。このプロパティは引数を取らず、戻り値としてDOMNodeListオブジェクトを返します。通常、HTMLの<!DOCTYPE>宣言には直接の子ノードは存在しないか、非常に特殊な場合にのみ現れます。

サンプルコードでは、まずHTML文字列を読み込み、DOMDocumentオブジェクトを作成します。そして、$dom->doctypeDOMDocumentTypeを取得し、そのchildNodesプロパティを参照して、子ノードの有無を確認しています。

次に、DOMXPathオブジェクトを使用してドキュメント内の特定の要素(例:<h1><body>)を検索し、それらの要素のchildNodesプロパティにアクセスして、直接の子ノードを取得する方法を示しています。要素のchildNodesプロパティも同様にDOMNodeListを返し、テキストノード(#text)やコメントノード(#comment)なども子ノードとして含まれることに注意してください。DOMNodeListは、取得した複数のノードをリスト形式で扱うためのオブジェクトです。このサンプルを通じて、HTMLやXMLドキュメントのツリー構造とノードの関係、およびXPathを使った要素の検索と子ノードの取得方法の基本を学ぶことができます。

DOMDocumentType::childNodesプロパティは、HTMLでは通常直接の子ノードを持たず、ほとんどの場合空になる点にご注意ください。一方、HTML要素(DOMElement)のchildNodesは、要素ノードだけでなく空白を含むテキストノード(#text)やコメントノード(#comment)も子ノードとして含みます。初心者は、目的の要素だけを抽出できないと迷いやすいため、nodeTypeで種類を判別し、trim()で空白テキストを処理するなどの対応を検討してください。XPathは、ドキュメント内の特定のノードを効率的に検索する強力な手段であり、DOMElement::childNodesと組み合わせることで、複雑なDOM構造から必要な情報を正確に抽出できます。サンプルコードの@によるエラー抑制はデバッグを困難にするため、本番環境では適切なエラーハンドリングとinstanceofによる型チェックを積極的に利用し、堅牢なコードを記述することをおすすめします。

関連コンテンツ

関連プログラミング言語