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

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

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

作成日: 更新日:

基本的な使い方

childNodesプロパティは、DOMツリー内のノードの子ノードをリストとして保持するプロパティです。このプロパティは、XMLドキュメントの構造をプログラムで操作するためのPHPのDOM拡張機能の一部として提供されます。

DOMNotationクラスは、XMLドキュメント型定義(DTD)内で宣言される「記法(notation)」を表すものです。記法は、XMLの外部にある非XML形式のデータを識別するために使われ、例えばMIMEタイプなどを指定する際に利用されます。

一般的なDOMノードにおいて、childNodesプロパティは、そのノードが直接持つすべての子ノードの集合をDOMNodeListオブジェクトとして返します。しかし、DOM仕様では、DOMNotationノードは子ノードを持つことができない特殊なノードタイプと定められています。

したがって、DOMNotationオブジェクトのchildNodesプロパティにアクセスした場合、返されるDOMNodeListオブジェクトは常に空となり、いかなる子ノードも含まれません。これは、DOMNotationノードがそれ自体で完結しており、内部に他の構造を持つことを意図されていないためです。このプロパティは読み取り専用であり、子ノードを追加したり削除したりすることはできません。

構文(syntax)

1<?php
2$xmlString = '<!DOCTYPE root [<!NOTATION gif SYSTEM "image/gif">]><root/>';
3$dom = new DOMDocument();
4$dom->loadXML($xmlString);
5
6// ドキュメントタイプから最初のNOTATIONノードを取得します。
7$notation = $dom->doctype->notations->item(0);
8
9// DOMNotationオブジェクトのchildNodesプロパティにアクセスします。
10// DOMNotationノードは子ノードを持たないため、これは常に空のDOMNodeListを返します。
11$childNodes = $notation->childNodes;
12
13// 取得したDOMNodeListの要素数を表示します。
14echo "DOMNotation childNodes length: " . $childNodes->length;
15?>

引数(parameters)

引数なし

引数はありません

戻り値(return)

DOMNodeList

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

サンプルコード

PHP DOM NotationのchildNodesを調べる

1<?php
2
3declare(strict_types=1);
4
5/**
6 * DOMNotationのchildNodesプロパティの使用例を示します。
7 *
8 * DOMNotationノードは、DTD(文書型定義)で定義される「記法」を表します。
9 * このノードは構造上、子ノードを持つことができません。
10 * このサンプルでは、childNodesプロパティが常に空のDOMNodeListを返すことを確認します。
11 */
12function showDomNotationChildNodes(): void
13{
14    // DTD内で記法(Notation) 'jpeg' を定義したXML文字列
15    $xmlString = <<<XML
16    <?xml version="1.0" encoding="UTF-8"?>
17    <!DOCTYPE root [
18      <!NOTATION jpeg SYSTEM "image/jpeg">
19      <!ELEMENT root EMPTY>
20    ]>
21    <root/>
22    XML;
23
24    // DOMDocumentオブジェクトを生成
25    $dom = new DOMDocument();
26
27    // DTDを読み込むオプションを付けてXMLをロードします。
28    // このオプションがないと、DTD内の情報は解析されません。
29    $dom->loadXML($xmlString, LIBXML_DTDLOAD);
30
31    // DocumentTypeノードから記法のリスト(DOMNamedNodeMap)を取得
32    $notations = $dom->doctype->notations;
33
34    // 'jpeg' という名前の記法 (DOMNotationオブジェクト) を取得
35    $jpegNotation = $notations->getNamedItem('jpeg');
36
37    if ($jpegNotation instanceof DOMNotation) {
38        // DOMNotationオブジェクトのchildNodesプロパティにアクセスします。
39        // このプロパティは子ノードのリスト(DOMNodeList)を返します。
40        $childNodes = $jpegNotation->childNodes;
41
42        // 記法ノードは子ノードを持てないため、リストの長さ(length)は常に0です。
43        echo "子ノードの数: " . $childNodes->length . PHP_EOL;
44
45        // childNodesプロパティの戻り値の型を確認します。
46        echo "戻り値の型: " . get_class($childNodes) . PHP_EOL;
47    } else {
48        echo "指定された記法が見つかりませんでした。";
49    }
50}
51
52// 関数を実行して結果を表示
53showDomNotationChildNodes();
54
55?>

DOMNotationクラスのchildNodesプロパティは、記法(Notation)ノードが持つすべての子ノードのリストを取得するために使用されます。このプロパティは引数を取りません。

戻り値は、子ノードの集合であるDOMNodeListオブジェクトです。しかし、XMLの仕様上、記法ノードは子要素やテキストなどを持つことができません。そのため、childNodesプロパティは常に空のDOMNodeListを返します。つまり、リストに含まれるノードの数は常に0になります。

サンプルコードでは、まずDTD(文書型定義)でjpegという記法を定義したXML文書を読み込みます。次に、このjpeg記法を表すDOMNotationオブジェクトを取得し、そのchildNodesプロパティにアクセスしています。プロパティが返すDOMNodeListオブジェクトのlengthプロパティ(リスト内のノード数)を出力することで、子ノードの数が0であることを確認できます。このコードは、DOMNotationノードが構造的に子を持たないという仕様を実際に示しています。

DOMNotationは、DTDで定義される「記法」を表す特殊なノードであり、XMLの構造上、子ノードを持つことができません。そのため、childNodesプロパティは常に空のDOMNodeListオブジェクトを返します。このプロパティのlengthは常に0であり、子ノードの繰り返し処理などに利用しようとしても、何も実行されない点に注意が必要です。また、サンプルコードのようにDTD内の記法情報を扱うには、loadXMLメソッドの第二引数にLIBXML_DTDLOADオプションを指定することが不可欠です。このオプションがないとDTDが解析されず、記法ノードを取得できません。getNamedItemは対象が見つからないとnullを返すため、プロパティにアクセスする前にinstanceofで型を確認することは安全なコードにつながります。

PHP DOMDocument childNodesで子ノード一覧を取得する

1<?php
2
3/**
4 * HTML文字列からDOMDocumentをロードし、特定の要素の子ノードを列挙する関数。
5 * システムエンジニアを目指す初心者向けに、DOMElementのchildNodesプロパティの
6 * 基本的な使い方を示すサンプルコードです。
7 *
8 * DOMNode::childNodes プロパティは DOMNodeList を返し、
9 * そのノードのすべての子ノード(要素、テキスト、コメントなど)を含みます。
10 */
11function demonstrateChildNodesProperty(): void
12{
13    // 1. DOMDocumentインスタンスを作成し、HTMLコンテンツをロードします。
14    // loadHTMLはHTMLをパースし、DOMツリーを構築します。
15    // @ を付けてエラー抑制していますが、実運用では適切なエラーハンドリングを推奨します。
16    $dom = new DOMDocument('1.0', 'UTF-8');
17    @$dom->loadHTML('
18        <!DOCTYPE html>
19        <html>
20        <head>
21            <title>DOM Example</title>
22        </head>
23        <body>
24            <h1>Welcome!</h1>
25            <p>This is a <span>sample</span> paragraph.</p>
26            <!-- This is a comment -->
27            <ul>
28                <li>Item 1</li>
29                <li>Item 2</li>
30            </ul>
31        </body>
32        </html>
33    ');
34
35    // 2. ドキュメントから特定の要素(ここでは'body'要素)を取得します。
36    // getElementsByTagNameはDOMNodeListを返すため、item(0)で最初の要素を取得します。
37    $bodyElement = $dom->getElementsByTagName('body')->item(0);
38
39    // 3. 'body'要素が取得できた場合のみ処理を続けます。
40    if ($bodyElement instanceof DOMElement) {
41        echo "--- 'body'要素の子ノード一覧 ---\n";
42
43        // 4. $bodyElement->childNodes プロパティにアクセスし、子ノードのリスト(DOMNodeList)を取得します。
44        // DOMNodeListは、要素ノードだけでなく、テキストノードやコメントノードなども含みます。
45        $childNodes = $bodyElement->childNodes;
46
47        // 5. DOMNodeListをループで処理し、各子ノードの情報を表示します。
48        foreach ($childNodes as $node) {
49            // nodeName: ノードの種類に応じた名前(例: 'h1', 'p', '#text', '#comment')
50            // nodeType: ノードの種類を示す定数(例: XML_ELEMENT_NODE, XML_TEXT_NODE, XML_COMMENT_NODE)
51            // nodeValue: ノードの内容(テキストノードのテキスト、コメントノードのコメントなど)
52
53            // テキストノードで空白のみの場合はスキップ(見やすくするため)
54            if ($node->nodeType === XML_TEXT_NODE && trim($node->nodeValue) === '') {
55                continue;
56            }
57
58            echo "  - ノード名: " . $node->nodeName;
59            echo ", タイプID: " . $node->nodeType;
60            // nodeValueが長い場合に備えて、最初の50文字まで表示
61            echo ", 値 (一部): " . mb_substr(trim($node->nodeValue), 0, 50) . (mb_strlen(trim($node->nodeValue)) > 50 ? '...' : '') . "\n";
62        }
63    } else {
64        echo "HTMLドキュメント内で'body'要素が見つかりませんでした。\n";
65    }
66}
67
68// 関数を実行して、サンプルコードの動作を確認します。
69demonstrateChildNodesProperty();

このサンプルコードは、PHPのDOM(Document Object Model)機能を使い、HTMLドキュメント内の特定の要素が持つ子ノードをプログラムで取得する方法を示しています。まず、DOMDocumentクラスを使ってHTML文字列をロードすることで、HTMLの構造をPHPのオブジェクトとして操作できるようになります。

次に、getElementsByTagNameメソッドで目的の要素(例えばbody要素)を取得します。このDOMElementオブジェクトから、childNodesプロパティにアクセスすることで、その要素が持つすべての子ノードのリストをDOMNodeListとして取得できます。childNodesプロパティは引数を取らず、戻り値としてDOMNodeListを返します。

DOMNodeListには、HTMLタグで囲まれた要素ノードだけでなく、タグ間の改行や空白などのテキストノード、さらにはコメントノードなど、様々な種類の子ノードが含まれます。取得したDOMNodeListforeachループで繰り返し処理が可能で、リスト内の各ノードについて、nodeNameでノードの種類に応じた名前、nodeTypeでノードのタイプID、nodeValueでノードの内容(テキストやコメント)といった情報を詳細に確認することができます。この一連の処理を通じて、HTMLドキュメントの構造をPHPで解析する基礎を学ぶことができます。

DOMNode::childNodes プロパティは、要素ノードだけでなく、HTMLの改行やインデントによって生成されるテキストノードやコメントノードも含む DOMNodeList を返します。要素ノードだけを処理したい場合は、取得した各ノードの nodeType プロパティが XML_ELEMENT_NODE かどうかを確認するか、PHP 5.3以降で利用可能な children プロパティの使用も検討してください。取得される DOMNodeList は、DOMツリーの変更がリアルタイムに反映される「ライブコレクション」です。そのため、リストを反復処理中に元のDOMツリーに変更を加えると、リストの内容が変化し予期せぬ動作につながる可能性があるため注意が必要です。また、DOMDocument::loadHTML は無効なHTMLをパースする際に警告を発することがありますので、実運用では @ でのエラー抑制ではなく、try-catch文やカスタムエラーハンドラを用いた堅牢なエラー処理を実装することが重要です。

PHP DOMNotation::childNodesとXPathでの子ノード取得

1<?php
2
3/**
4 * DOMNotationクラスのchildNodesプロパティと、一般的なDOM要素のchildNodesプロパティ、
5 * そしてXPathの基本的な使用方法を組み合わせたサンプルコードです。
6 *
7 * DOMNotationノードはXMLのDTD内で定義される表記情報であり、DOM仕様上、子ノードを持つことはありません。
8 * そのため、DOMNotation::childNodesプロパティは常に空のDOMNodeListを返します。
9 *
10 * 一方、一般的なXML要素ノード(DOMElement)は、テキストノード、コメントノード、他の要素ノードなどを
11 * 子ノードとして持つことがあり、そのchildNodesプロパティはこれらの子ノードのリストを返します。
12 * XPathは、XMLドキュメントから特定のノードを選択するために強力なツールです。
13 *
14 * @param string $xmlString DTDにNOTATION定義を含む、あるいは要素を持つXML文字列
15 * @return void
16 */
17function demonstrateDomNodesAndChildNodes(string $xmlString): void
18{
19    $dom = new DOMDocument();
20    // 厳密なエラーチェックを無効にして、DTDの構文エラーで処理が停止しないようにする
21    $dom->validateOnParse = true;
22    $dom->loadXML($xmlString, LIBXML_DTDLOAD | LIBXML_DTDATTR);
23
24    echo "--- DOMNotation::childNodesのデモンストレーション ---\n";
25    // DOMDocument::doctypeからDOMDocumentTypeノードを取得し、そのnotationsプロパティにアクセス
26    if ($dom->doctype && $dom->doctype->notations) {
27        echo "XMLドキュメントのDTDに定義されたNOTATION情報を確認します。\n";
28        foreach ($dom->doctype->notations as $notationName => $notationNode) {
29            if ($notationNode instanceof DOMNotation) {
30                echo "  NOTATION名: " . $notationName . "\n";
31                // DOMNotationノードは子ノードを持たないため、childNodesは常に空です。
32                $childNodes = $notationNode->childNodes;
33                echo "    DOMNotationのchildNodesの数: " . $childNodes->length . " (常に0です)\n";
34                echo "    補足: DOMNotationはDTDの定義であり、一般的な要素のように子ノードを持つことはありません。\n";
35            }
36        }
37    } else {
38        echo "  このXMLドキュメントにはDTDまたはNOTATION定義がありません。\n";
39    }
40
41    echo "\n--- XPathと一般的なDOM要素のchildNodesのデモンストレーション ---\n";
42    // DOMXPathオブジェクトを作成し、XPathクエリを使用して特定の要素を選択します。
43    $xpath = new DOMXPath($dom);
44
45    // XPathクエリで'/document/item'パスにあるすべての'item'要素を選択
46    $items = $xpath->query('/document/item');
47
48    if ($items->length > 0) {
49        echo "XPath '/document/item' で " . $items->length . " 個の要素が見つかりました。\n";
50        foreach ($items as $itemElement) {
51            // 選択したDOMElementのchildNodesプロパティにアクセス
52            echo "  要素名: " . $itemElement->nodeName . ", 属性id: " . $itemElement->getAttribute('id') . "\n";
53            $itemChildNodes = $itemElement->childNodes;
54            echo "    子ノードの数: " . $itemChildNodes->length . "\n";
55
56            // 子ノードが存在する場合、それらをリスト表示
57            if ($itemChildNodes->length > 0) {
58                echo "    子ノード一覧:\n";
59                foreach ($itemChildNodes as $childNode) {
60                    echo "      - 名前: " . $childNode->nodeName . " (型: " . $childNode->nodeType . ", 値: '" . trim($childNode->nodeValue) . "')\n";
61                }
62            } else {
63                echo "    この要素には子ノードがありません (空白文字ノードを除く)。\n";
64            }
65        }
66    } else {
67        echo "  XPathクエリ '/document/item' に一致する要素は見つかりませんでした。\n";
68    }
69}
70
71// DTDでNOTATIONが定義され、かつ一般的なXML要素も含むサンプルXML
72// item要素にはテキストコンテンツがあり、そのchildNodesプロパティにはテキストノードが含まれます。
73$sampleXml = <<<XML
74<!DOCTYPE document [
75<!NOTATION svg SYSTEM "image/svg+xml">
76<!NOTATION png SYSTEM "image/png">
77<!ELEMENT document (item*)>
78<!ELEMENT item (#PCDATA)>
79<!ATTLIST item
80  id ID #REQUIRED
81  type NOTATION #REQUIRED
82>
83]>
84<document>
85  <item id="i1" type="svg">これはSVG形式の画像に関する説明です。</item>
86  <item id="i2" type="png"></item>
87</document>
88XML;
89
90// 定義した関数を実行
91demonstrateDomNodesAndChildNodes($sampleXml);

このサンプルコードは、PHPのDOM拡張機能におけるDOMNotation::childNodesプロパティの振る舞いと、一般的なDOM要素のchildNodesプロパティ、さらにXPathの基本的な利用方法を解説しています。DOMNotationクラスのchildNodesプロパティは、XMLのDTD(Document Type Definition)で定義される表記情報を扱います。このプロパティは引数を取らず、戻り値としてDOMNodeListを返しますが、DOMNotationノード自体は子ノードを持たないため、常に空のDOMNodeList(長さが0)が返されます。

一方、サンプルコードではXPathも活用し、XMLドキュメント内の一般的な要素ノードの子ノード取得も示しています。DOMXPathオブジェクトを使用することで、複雑なXML構造から特定の要素を効率的に選択できます。選択されたDOMElementchildNodesプロパティは、その要素が持つテキストノードや他の要素ノードなどの子ノードをDOMNodeListとして返します。これにより、DOMNotationが子ノードを持たない特殊なケースと、一般的な要素が子ノードを持つ場合の明確な違いを理解できます。

このサンプルコードでは、DOMNotationクラスのchildNodesプロパティが常に空のDOMNodeListを返す点に注意が必要です。これは、DOMNotationがXMLのDTD内で定義される表記情報であり、一般的なXML要素のように子ノードを持つ構造ではないためです。この挙動は仕様であり、エラーではありません。

一方、一般的なDOMElementchildNodesプロパティは、要素内のテキストノードや他の要素ノード、コメントノードなど、あらゆる種類の子ノードをリストとして返します。特に、要素間の改行やインデントもテキストノードとして含まれる場合があるため、trim()関数などで不要な空白文字を除去すると、意図した通りの処理を行いやすくなります。

また、DOMXPathはXMLドキュメントから特定のノードを柔軟かつ強力に選択できるツールです。複雑な階層構造の中から目的の要素を効率的に見つけ出す際に非常に役立ちますので、その基本的な使い方を習得しておくことをお勧めします。DTD定義を含むXMLを扱う場合は、DOMDocument::loadXML()関数などでLIBXML_DTDLOADオプションを忘れずに指定してください。

関連コンテンツ

関連プログラミング言語

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