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

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

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

作成日: 更新日:

基本的な使い方

childNodesプロパティは、Dom\Entityオブジェクトが持つ子ノードのリストを保持するプロパティです。Dom\Entityは、XMLやHTMLドキュメント内で定義された実体(エンティティ)を表す特殊なノードです。例えば、XMLドキュメントのDTD(Document Type Definition)で定義されたエンティティがドキュメント内で参照された場合、そのエンティティの実体の内容がパースされ、その結果として生じる子ノード群がこのchildNodesプロパティによって提供されます。

このプロパティが保持する値は、Dom\NodeListオブジェクトです。Dom\NodeListは、読み取り専用のノードのコレクションであり、エンティティの実体に含まれるすべての子要素やテキストノードなどを、定義された順序で参照することを可能にします。これにより、エンティティが実際に展開されたときにどのような構造や内容を持つのかをプログラムから詳細に調べることができます。

具体的には、ドキュメント内でエンティティ参照を見つけ、その実体がどのような構成になっているかを解析したい場合に、このchildNodesプロパティを利用します。例えば、エンティティが複数のテキストノードや要素ノードから構成されている場合、それらのノードにアクセスして内容を抽出したり、特定の条件に基づいて処理を行ったりする際に非常に有用です。このプロパティは、複雑なXMLドキュメントの構造を理解し、その中から特定の情報を抽出する作業において、重要な役割を果たします。

構文(syntax)

1<?php
2$document = new Dom\Document();
3$document->loadXML('<!DOCTYPE root [<!ENTITY myentity "entity content">]><root/>');
4$entity = $document->doctype->entities->item(0);
5
6$childNodesList = $entity->childNodes;

引数(parameters)

引数なし

引数はありません

戻り値(return)

Dom\NodeList

Dom\Entity オブジェクトの子ノードのリストを Dom\NodeList オブジェクトとして返します。

サンプルコード

PHP DOM childNodesでエンティティ子ノード表示

1<?php
2
3/**
4 * Dom\EntityのchildNodesプロパティの使用例を示します。
5 *
6 * この関数は、DTD(文書型定義)で宣言されたエンティティを取得し、
7 * そのエンティティが持つ子ノードのリストを走査して情報を表示します。
8 */
9function displayEntityChildNodes(): void
10{
11    // DTDでエンティティを定義したXML文字列。
12    // エンティティ'user_info'は、テキストノードと要素ノード(<b>)を含んでいます。
13    $xmlString = <<<XML
14    <?xml version="1.0" encoding="UTF-8"?>
15    <!DOCTYPE profile [
16      <!ENTITY user_info "Name: Alex, Role: <b>Developer</b>.">
17    ]>
18    <profile>
19      <user>&user_info;</user>
20    </profile>
21    XML;
22
23    // DOMDocumentオブジェクトを生成します
24    $doc = new DOMDocument();
25
26    // DTDをロードするためにオプションを指定してXMLを読み込みます
27    // このオプションがないと、doctypeプロパティがnullになる場合があります
28    $doc->loadXML($xmlString, LIBXML_DTDLOAD);
29
30    // DocumentTypeノード (<!DOCTYPE ...> の部分) を取得します
31    $doctype = $doc->doctype;
32    if ($doctype === null) {
33        echo "DOCTYPEが見つかりません。" . PHP_EOL;
34        return;
35    }
36
37    // 'entities'プロパティから、宣言されたエンティティのリストを取得します
38    // これは DOMNamedNodeMap を返します
39    $entities = $doctype->entities;
40
41    // 名前を指定して 'user_info' エンティティ(Dom\Entity)を取得します
42    /** @var DOMEntity|null $entity */
43    $entity = $entities->getNamedItem('user_info');
44    if ($entity === null) {
45        echo "エンティティ 'user_info' が見つかりませんでした。" . PHP_EOL;
46        return;
47    }
48
49    echo "エンティティ '{$entity->nodeName}' の子ノード一覧:" . PHP_EOL;
50    echo "-----------------------------------------" . PHP_EOL;
51
52    // childNodesプロパティで子ノードのリスト(Dom\NodeList)を取得します
53    $childNodes = $entity->childNodes;
54
55    // 子ノードが存在するかチェックします
56    if ($childNodes->length > 0) {
57        // NodeListをループして、各子ノードの情報を表示します
58        foreach ($childNodes as $index => $child) {
59            /** @var DOMNode $child */
60            // nodeType 3はテキストノード、1は要素ノードです
61            echo sprintf(
62                "[%d] NodeType: %-2d | NodeName: %-8s | NodeValue: '%s'\n",
63                $index,
64                $child->nodeType,
65                $child->nodeName,
66                trim($child->nodeValue ?? $child->textContent)
67            );
68        }
69    } else {
70        echo "子ノードはありません。" . PHP_EOL;
71    }
72}
73
74// 関数を実行して結果を表示します
75displayEntityChildNodes();
76

Dom\EntityクラスのchildNodesプロパティは、XMLのDTD(文書型定義)で定義されたエンティティが持つ子ノードのリストを取得するために使用します。このプロパティは引数を取らず、戻り値として子ノードの集合であるDom\NodeListオブジェクトを返します。

サンプルコードでは、まずDTD内でuser_infoという名前のエンティティを定義したXML文字列を用意しています。このエンティティは、テキストと<b>要素で構成されています。次にDOMDocumentオブジェクトを使ってこのXMLを読み込み、getNamedItemメソッドでuser_infoエンティティ(Dom\Entityオブジェクト)を取得します。

続いて、$entity->childNodesという形でchildNodesプロパティにアクセスし、エンティティが持つすべての子ノードをDom\NodeListとして取得します。このNodeListは配列のようにforeachループで処理できるため、各子ノードを順番に取り出し、その種類(nodeType)、名前(nodeName)、値(nodeValue)を表示しています。この結果、user_infoエンティティが「テキストノード」と「b要素ノード」から構成されていることがわかります。このようにchildNodesプロパティは、エンティティの内部構造をプログラムで詳細に分析する際に役立ちます。

childNodesプロパティは、要素だけでなくテキストノードも含むDom\NodeListを返します。改行やインデントのための空白文字もテキストノードとして認識されるため、ループ処理では意図しないノードが含まれる可能性に注意が必要です。サンプルにあるようにDTDで定義されたエンティティを扱うには、loadXMLメソッドの第二引数にLIBXML_DTDLOAD定数を指定することが不可欠です。これを忘れるとエンティティが正しく読み込まれません。また、doctypeプロパティやgetNamedItemメソッドは対象が見つからない場合にnullを返すため、必ずnullチェックを行いましょう。要素ノードのnodeValuenullになるため、テキスト内容を取得するにはtextContentプロパティの利用が適切です。

PHP DOM: Entity childNodes を取得する

1<?php
2
3/**
4 * Dom\Entity::childNodes プロパティのデモンストレーション関数。
5 *
6 * XMLドキュメント内で定義されたエンティティの子ノードを取得する方法を示します。
7 * Dom\Entity は通常、DTD (Document Type Definition) 内で定義され、
8 * その内容が Dom\NodeList として childNodes プロパティからアクセスできます。
9 */
10function demonstrateDomEntityChildNodes(): void
11{
12    // 1. 新しい Dom\Document オブジェクトを作成します。
13    $dom = new Dom\Document();
14
15    // 2. DTD (Document Type Definition) でエンティティを定義したXML文字列をロードします。
16    // 'myentity' という名前のエンティティは、テキストとHTML要素を含む内容を持っています。
17    // Dom\Entity::childNodes は、このエンティティの内容を表すノードのリストを返します。
18    $xmlString = <<<XML
19<!DOCTYPE root [
20  <!ENTITY myentity "これはエンティティの内容です。<b>太字のテキスト</b>も含まれます。">
21]>
22<root/>
23XML;
24
25    $dom->loadXML($xmlString);
26
27    echo "Dom\\Entity::childNodes プロパティのデモンストレーション:\n\n";
28
29    // 3. ドキュメントの Dom\DocumentType オブジェクトを取得します。
30    // ドキュメントタイプには、エンティティ、要素、属性などの定義が含まれます。
31    $docType = $dom->doctype;
32
33    if ($docType instanceof Dom\DocumentType) {
34        echo "ドキュメントタイプが正常にロードされました。\n";
35
36        // 4. Dom\DocumentType から定義済みのエンティティのリスト (Dom\NamedNodeMap) を取得します。
37        $entities = $docType->entities;
38
39        if ($entities->count() > 0) {
40            echo "DTD内で " . $entities->count() . " 個のエンティティが見つかりました。\n";
41
42            // 5. 'myentity' という名前の Dom\Entity オブジェクトを探します。
43            $myEntity = null;
44            foreach ($entities as $entityNode) {
45                if ($entityNode instanceof Dom\Entity && $entityNode->nodeName === 'myentity') {
46                    $myEntity = $entityNode;
47                    break;
48                }
49            }
50
51            if ($myEntity) {
52                echo "エンティティ '{$myEntity->nodeName}' が見つかりました。\n";
53
54                // 6. Dom\Entity::childNodes プロパティにアクセスします。
55                // このプロパティは Dom\NodeList オブジェクトを返し、エンティティの内容を構成する
56                // 子ノード (テキストノード、要素ノードなど) を含みます。
57                $childNodes = $myEntity->childNodes;
58
59                echo "エンティティ '{$myEntity->nodeName}' の子ノードを列挙します:\n";
60                if ($childNodes->count() > 0) {
61                    foreach ($childNodes as $index => $childNode) {
62                        echo "  - 子ノード " . ($index + 1) . ":\n";
63                        echo "    ノード名: " . $childNode->nodeName . " (タイプ: " . $childNode->nodeType . ")\n";
64                        // テキストノードの場合、その内容を表示します。
65                        if ($childNode->nodeType === Dom\Node::TEXT_NODE) {
66                            echo "    ノード値: '" . trim($childNode->nodeValue) . "'\n";
67                        }
68                        // 要素ノードの場合、そのタグ名を表示します。
69                        if ($childNode->nodeType === Dom\Node::ELEMENT_NODE) {
70                             echo "    タグ名: '" . $childNode->tagName . "'\n";
71                        }
72                    }
73                } else {
74                    echo "  このエンティティには子ノードが見つかりませんでした。\n";
75                }
76            } else {
77                echo "警告: エンティティ 'myentity' は見つかりませんでした。\n";
78            }
79        } else {
80            echo "情報: ドキュメントタイプにエンティティは定義されていませんでした。\n";
81        }
82    } else {
83        echo "エラー: XMLドキュメントに有効なDOCTPYPE定義が見つかりませんでした。\n";
84    }
85}
86
87// 関数を実行してデモンストレーションを開始します。
88demonstrateDomEntityChildNodes();

Dom\Entity::childNodesは、XMLドキュメントのDTD(Document Type Definition)で定義されたエンティティの内部に含まれる子ノードのリストを取得するためのプロパティです。このプロパティには引数はなく、戻り値としてDom\NodeListオブジェクトを返します。Dom\NodeListは、エンティティの内容を構成するテキストノードや要素ノードなど、複数のノードを順序付けられたリストとして扱います。

このサンプルコードでは、まずDTD内で「myentity」という名前のエンティティを定義したXMLドキュメントをロードします。このエンティティの内容は、通常のテキストと太字のHTML要素(<b>タグ)を含んでいます。次に、ドキュメントのタイプ情報(Dom\DocumentType)から、定義されているエンティティのリスト(Dom\NamedNodeMap)を取得します。そのリストの中から「myentity」という名前のDom\Entityオブジェクトを特定した後、そのchildNodesプロパティにアクセスします。取得したDom\NodeListをループ処理することで、エンティティの内容を構成する各子ノード(例えば、テキストノードや<b>要素ノード)のタイプや値、名前などを順に表示し、エンティティの内部構造をプログラム的に分析する方法を示しています。これにより、XMLのエンティティに定義された複雑な内容も容易に操作できるようになります。

Dom\Entity::childNodesプロパティは、XMLのDTD(Document Type Definition)内で定義されたエンティティの内容をDom\NodeListとして取得します。このプロパティへアクセスするには、Dom\DocumentTypeから対象のDom\Entityオブジェクトを正しく取得する必要があります。エンティティはDTD定義に依存するため、一般的なWeb開発で直接操作する機会は稀です。返されるNodeListは複数の子ノードを含むため、ループ処理で各ノードの型を確認しながら利用することが重要です。XMLのDTD概念と、ロード失敗やエンティティが見つからない場合の適切なエラーハンドリングを忘れずに行ってください。

PHP XPathで要素の子ノードを列挙する

1<?php
2
3/**
4 * HTMLドキュメントからXPathを使用して要素を選択し、その子ノードを列挙するサンプル関数。
5 *
6 * システムエンジニアを目指す初心者向けに、PHPのDOM拡張機能とXPathの基本的な使い方、
7 * そして選択したノードの子ノードへのアクセス方法を簡潔に示します。
8 * Dom\Entity クラスはDom\Nodeを継承しているためchildNodesプロパティを持ちますが、
9 * 実際にはDom\Elementのような一般的な要素ノードでこのプロパティを使用することが多いため、
10 * より実用的な例としてDom\Elementの子ノードを扱います。
11 */
12function demonstrateChildNodesWithXPath(): void
13{
14    // 1. 解析するサンプルHTMLドキュメントを文字列で定義します。
15    $html = <<<HTML
16<!DOCTYPE html>
17<html>
18<head>
19    <title>サンプルページ</title>
20</head>
21<body>
22    <div id="main-content">
23        <h1>メインコンテンツのタイトル</h1>
24        <p>最初の段落です。</p>
25        <!-- ここにコメントノードがあります -->
26        <span>重要な情報</span>
27        テキストノードも子ノードです
28    </div>
29    <div id="sidebar">
30        <p>サイドバーの内容</p>
31    </div>
32</body>
33</html>
34HTML;
35
36    // 2. Dom\Documentオブジェクトを初期化し、HTML文字列を読み込みます。
37    // LIBXML_HTML_NOIMPLIED と LIBXML_HTML_NODEFDTD は、
38    // 余分な<html>や<!DOCTYPE>が自動追加されるのを防ぎ、より元のHTMLに近いDOMツリーを生成します。
39    $dom = new Dom\Document();
40    // loadHTMLでエラーが発生する可能性があるので、エラー抑制演算子@を使用しています。
41    // 実際にはエラーハンドリングを行うことが推奨されます。
42    @$dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
43
44    // 3. Dom\XPathオブジェクトを作成し、DOMドキュメントに対してXPathクエリを実行できるようにします。
45    $xpath = new Dom\XPath($dom);
46
47    // 4. XPathクエリを使用して特定の要素を選択します。
48    // ここでは、idが "main-content" のdiv要素を検索します。
49    // Dom\XPath::query() は Dom\NodeList オブジェクトを返します。
50    $nodes = $xpath->query("//div[@id='main-content']");
51
52    if ($nodes->length > 0) {
53        // XPathクエリに一致する最初のノード(この場合は div#main-content)を取得します。
54        /** @var Dom\Element $mainContentElement */
55        $mainContentElement = $nodes->item(0);
56
57        echo "--- XPathで選択した要素 ('div#main-content') の子ノード ---" . PHP_EOL;
58        echo "親要素のタグ名: '{$mainContentElement->nodeName}'" . PHP_EOL . PHP_EOL;
59
60        // 5. 選択した要素の childNodes プロパティにアクセスします。
61        // childNodes プロパティは Dom\NodeList オブジェクトを返します。
62        // このリストには、要素ノードだけでなく、テキストノードやコメントノードなども含まれます。
63        $childNodes = $mainContentElement->childNodes;
64
65        if ($childNodes->length > 0) {
66            echo "合計子ノード数: " . $childNodes->length . PHP_EOL;
67            foreach ($childNodes as $index => $childNode) {
68                echo "-----------------------------------" . PHP_EOL;
69                echo "子ノード " . ($index + 1) . ":" . PHP_EOL;
70                echo "  タイプ: " . $childNode->nodeType;
71                echo " (";
72                // ノードタイプを可読な文字列に変換して表示します。
73                echo match ($childNode->nodeType) {
74                    XML_ELEMENT_NODE => "要素ノード (タグ)",
75                    XML_TEXT_NODE => "テキストノード",
76                    XML_COMMENT_NODE => "コメントノード",
77                    XML_DOCUMENT_TYPE_NODE => "文書型宣言ノード",
78                    XML_CDATA_SECTION_NODE => "CDATAセクションノード",
79                    XML_PROCESSING_INSTRUCTION_NODE => "処理命令ノード",
80                    XML_ATTRIBUTE_NODE => "属性ノード",
81                    XML_ENTITY_REF_NODE => "エンティティ参照ノード",
82                    XML_ENTITY_NODE => "エンティティノード", // Dom\Entity はこのタイプ
83                    XML_NOTATION_NODE => "記法ノード",
84                    default => "不明なノードタイプ",
85                };
86                echo ")" . PHP_EOL;
87                echo "  名前: " . $childNode->nodeName . PHP_EOL; // 要素ノードならタグ名、テキストノードなら #text
88                // テキストノードやコメントノードの場合、その内容も表示します。
89                if ($childNode->nodeType === XML_TEXT_NODE || $childNode->nodeType === XML_COMMENT_NODE) {
90                    $value = trim($childNode->nodeValue);
91                    if ($value !== '') { // 空白のみのテキストノードはスキップ
92                        echo "  内容: '" . $value . "'" . PHP_EOL;
93                    }
94                }
95            }
96        } else {
97            echo "選択された要素には子ノードがありませんでした。" . PHP_EOL;
98        }
99    } else {
100        echo "XPathクエリ '//div[@id=\"main-content\"]' に一致する要素が見つかりませんでした。" . PHP_EOL;
101    }
102}
103
104// 上記で定義したサンプル関数を実行します。
105demonstrateChildNodesWithXPath();

このサンプルコードは、PHPのDOM拡張機能とXPathを使ってHTMLドキュメントを解析し、特定の要素の子ノードを効率的に取得する方法を示しています。まず、HTML文字列をDom\Documentに読み込み、Dom\XPathを利用してidが"main-content"のdiv要素を特定します。この特定したDom\ElementオブジェクトからchildNodesプロパティにアクセスすることで、直接その要素のすべての子ノードリストを取得できます。

childNodesプロパティは引数を取らず、戻り値としてDom\NodeListオブジェクトを返します。このリストには、HTMLのタグとして表現される要素ノードだけでなく、タグ間の空白やテキスト、コメントなども含まれる点が特徴です。サンプルでは、取得したDom\NodeListを反復処理し、各子ノードのタイプや名前、内容を表示することで、HTML構造がどのように認識されているかを確認できます。これにより、HTMLドキュメントの内部構造をプログラムで詳細に調べ、操作するための基本的な手法を理解できます。

Dom\EntitychildNodesプロパティは、HTMLドキュメント内の要素だけでなく、要素間の空白や改行、コメントなども含めた全ての子ノードをDom\NodeListとして返します。特に意図しない空のテキストノードが含まれることがあるため、処理する際にはnodeTypeプロパティでノードの種類を確認し、nodeValuetrimして内容が空でないかをチェックすると良いでしょう。また、サンプルコードではDom\Elementの例を示しましたが、Dom\Entityを含むDom\Nodeを継承する多くのクラスで利用可能です。loadHTMLのようなDOM操作は失敗する可能性があるため、エラー抑制演算子@は避け、必ず適切なエラーハンドリングを実装してください。これは堅牢なシステム開発の基本です。

関連コンテンツ

関連プログラミング言語

【PHP8.x】Dom\Entity::childNodesプロパティの使い方 | いっしー@Webエンジニア