【PHP8.x】Dom\EntityReference::ownerDocumentプロパティの使い方
ownerDocumentプロパティの使い方について、初心者にもわかりやすく解説します。
基本的な使い方
ownerDocumentプロパティは、このエンティティ参照ノードが属しているDom\Documentオブジェクトを保持するプロパティです。XMLやHTMLのドキュメントは、要素やテキストといった多数のノードが階層構造をなすツリーとして表現されます。このプロパティは、現在操作しているノードが、そのツリー全体のどのドキュメントに所属しているかを示します。このプロパティは読み取り専用であり、一度ドキュメントに所属したノードの所属先を直接書き換えることはできません。これにより、ドキュメントの構造的な整合性が保たれます。例えば、あるノードを取得した後に、そのノードと同じドキュメント内に新しい要素を追加したい場合、$node->ownerDocument->createElement()のように記述することで、所属ドキュメントのメソッドを呼び出すことができます。なお、new Dom\EntityReference()などでノードが作成された直後で、まだどのドキュメントにも追加されていない場合、このプロパティはnullを返します。このように、あるノードからドキュメント全体への参照を取得するための重要な役割を担っています。
構文(syntax)
1<?php 2 3$doc = new \Dom\Document(); 4 5$entityRef = $doc->createEntityReference('example'); 6 7$owner = $entityRef->ownerDocument; 8 9var_dump($owner === $doc); 10 11?>
引数(parameters)
引数なし
引数はありません
戻り値(return)
?Dom\Document
このプロパティは、この要素が属しているDOMドキュメントオブジェクトを返します。要素がドキュメントに属していない場合、nullが返されます。
サンプルコード
ownerDocumentで所有ドキュメントをsaveHTMLする
1<?php 2 3/** 4 * Demonstrates the use of Dom\EntityReference::ownerDocument and Dom\Document::saveHTML. 5 * 6 * This function creates a new DOM document, adds an entity reference to it, 7 * then retrieves the owner document from the entity reference and saves its HTML. 8 */ 9function demonstrateDomEntityReferenceOwnerDocument(): void 10{ 11 // 1. 新しい Dom\Document オブジェクトを作成します。 12 // HTML5 のドキュメントとして扱うため、明示的に '1.0' と 'UTF-8' を指定します。 13 $document = new Dom\Document('1.0', 'UTF-8'); 14 15 // DOM ツリーの構造が崩れないよう、基本的なHTML要素を作成します。 16 $htmlElement = $document->createElement('html'); 17 $bodyElement = $document->createElement('body'); 18 $paragraphElement = $document->createElement('p', 'これは段落です。記号: '); 19 20 // 2. エンティティ参照 (例: '&' に対応する 'amp') を作成します。 21 // この時点で、Dom\EntityReference の ownerDocument は $document になります。 22 $entityReference = $document->createEntityReference('amp'); 23 24 // 作成したエンティティ参照ノードを段落に追加し、段落をボディに、ボディをHTMLに追加します。 25 $paragraphElement->appendChild($entityReference); 26 $bodyElement->appendChild($paragraphElement); 27 $htmlElement->appendChild($bodyElement); 28 $document->appendChild($htmlElement); 29 30 // ドキュメントの内容をHTML形式で出力します。 31 // ここで '&' が '&' として出力されるのは、HTMLの標準的なレンダリング挙動です。 32 echo "--- ドキュメントツリーに追加された後のHTML出力 ---\n"; 33 echo $document->saveHTML() . "\n\n"; 34 35 // 3. Dom\EntityReference オブジェクトの ownerDocument プロパティにアクセスします。 36 // このプロパティは、そのノードが属する Dom\Document オブジェクトを返します。 37 $ownerDocument = $entityReference->ownerDocument; 38 39 // ownerDocument が正しく取得できたか確認します。 40 if ($ownerDocument instanceof Dom\Document) { 41 echo "--- エンティティ参照から取得した所有ドキュメントのHTML出力 ---\n"; 42 // 4. 取得した所有ドキュメントオブジェクトに対して saveHTML() メソッドを呼び出します。 43 // これは元の $document オブジェクトと同じ内容を出力します。 44 echo $ownerDocument->saveHTML() . "\n"; 45 46 // 取得した ownerDocument が元の $document と同じインスタンスであるか検証します。 47 if ($ownerDocument === $document) { 48 echo "\n(検証: 取得した ownerDocument は元のドキュメントと同じインスタンスです。)\n"; 49 } else { 50 echo "\n(検証: 取得した ownerDocument は元のドキュメントと異なるインスタンスです。)\n"; 51 } 52 } else { 53 echo "エンティティ参照から所有ドキュメントを取得できませんでした。\n"; 54 } 55} 56 57// 上記のデモンストレーション関数を実行します。 58demonstrateDomEntityReferenceOwnerDocument();
このPHPサンプルコードは、HTMLのようなドキュメントをプログラムで操作する際に使う「DOM(Document Object Model)」の基本的な概念と、特定の要素がどのドキュメントに属しているかを確認する方法を示しています。
まず、新しいDom\Documentオブジェクトを作成し、基本的なHTML構造と「&」のような特別な記号(エンティティ参照)を追加しています。Dom\EntityReference::ownerDocumentプロパティは、このエンティティ参照がどのDom\Documentオブジェクトに属しているかを示すものです。このプロパティには引数はなく、そのノードが属するDom\Documentオブジェクト、またはノードがまだどのドキュメントにも属していない場合はnullを返します。
サンプルでは、エンティティ参照をドキュメントに追加した後、そのownerDocumentプロパティにアクセスして、参照元のDom\Documentオブジェクトを取得しています。これにより、エンティティ参照が元のドキュメントに正しく結びついていることを確認できます。
さらに、Dom\Document::saveHTML()メソッドが使われています。このメソッドは、Dom\Documentオブジェクトが現在保持している内容を、HTML形式の文字列として出力する役割を持っています。サンプルコードでは、最初に作成したドキュメントと、ownerDocumentプロパティで取得したドキュメントの両方でsaveHTML()を呼び出し、全く同じHTMLが出力されることを示しています。これは、ownerDocumentプロパティが元のドキュメントインスタンスそのものを返していることを明確に証明しています。このコードを通じて、DOMツリー内の各ノードが自身の「親」となるドキュメントとどのように関連しているかを具体的に理解することができます。
Dom\EntityReference::ownerDocumentプロパティは、エンティティ参照ノードが属するDom\Documentオブジェクトそのものを返します。このプロパティが新しいドキュメントを生成するわけではありません。ノードがドキュメントツリーに追加されると、そのドキュメントインスタンスが設定されます。
Dom\Document::saveHTML()メソッドは、構築されたDOMツリー全体をHTML形式の文字列として出力します。この際、&のようなエンティティ参照はHTMLの標準的な表記に従い、&などの対応する文字に変換されて出力されますので、出力内容を確認する際はご注意ください。
安全かつ正確なDOM操作のため、Dom\Documentオブジェクトを初期化する際は、文字コードやXML宣言などを適切に指定し、<html>や<body>といったHTMLの基本構造を整えておくことをお勧めします。
Dom\EntityReferenceのownerDocumentを取得する
1<?php 2 3// このサンプルコードは、PHP 8の新しいDom拡張のDom\EntityReferenceクラスに焦点を当てています。 4// Dom\EntityReferenceは、XMLやHTMLドキュメント内で定義されたエンティティ(例: &entity_name;)への参照を表すノードです。 5// ownerDocumentプロパティは、そのエンティティ参照が属しているDom\Documentオブジェクトを返します。 6 7// DTD(Document Type Definition)でエンティティを定義したXML文字列を用意します。 8// LIBXML_NOENTオプションを使用すると、このエンティティ参照がDom\EntityReferenceノードとしてパースされます。 9$xmlString = <<<XML 10<!DOCTYPE doc [ 11 <!ENTITY myentity "Hello from an entity!"> 12]> 13<root> 14 <message>&myentity;</message> 15</root> 16XML; 17 18// 新しいDom\Documentオブジェクトを作成します。 19$document = new Dom\Document(); 20 21// XML文字列を読み込みます。 22// LIBXML_NOENT: エンティティ参照を展開せずに、Dom\EntityReferenceノードとして残すためのオプション。 23// これがないと、&myentity; は「Hello from an entity!」というテキストに展開されてしまいます。 24// LIBXML_DTDLOAD: DTDをロードして、エンティティ定義(<!ENTITY ...>)を認識させるためのオプション。 25// これにより、&myentity; が有効なエンティティ参照として扱われます。 26$document->loadXML($xmlString, LIBXML_NOENT | LIBXML_DTDLOAD); 27 28// Dom\XPathオブジェクトを作成し、ドキュメント内のノードを検索するために使用します。 29$xpath = new Dom\XPath($document); 30 31// XPathクエリを使用して、ドキュメント内のすべてのノードを取得します。 32// その後、PHPのコードでDom\EntityReferenceノードに該当するものをフィルタリングします。 33// '//* | //@* | //processing-instruction() | //comment() | //text()' は、すべてのノードタイプを取得する一般的なクエリです。 34$allNodes = $xpath->query('//* | //@* | //processing-instruction() | //comment() | //text()'); 35 36$entityReferenceNode = null; 37foreach ($allNodes as $node) { 38 // 検索結果のノードがDom\EntityReferenceのインスタンスであり、 39 // かつそのノード名が定義したエンティティ名(例: 'myentity')と一致するかを確認します。 40 // Dom\EntityReferenceのnodeTypeはXML_ENTITY_REF_NODE(値は6)です。 41 if ($node instanceof Dom\EntityReference && $node->nodeName === 'myentity') { 42 $entityReferenceNode = $node; 43 break; // 目的のノードが見つかったのでループを終了 44 } 45} 46 47// Dom\EntityReferenceノードが見つかったかどうかをチェックします。 48if ($entityReferenceNode) { 49 echo "Dom\\EntityReferenceノードが見つかりました。\n"; 50 echo "ノード名: " . $entityReferenceNode->nodeName . "\n"; 51 echo "ノードタイプ: " . $entityReferenceNode->nodeType . " (XML_ENTITY_REF_NODEは6)\n"; 52 53 // ここがメインの部分です: Dom\EntityReferenceのownerDocumentプロパティにアクセスします。 54 // このプロパティは、このノードが属するDom\Documentオブジェクトを返します。 55 $ownerDocument = $entityReferenceNode->ownerDocument; 56 57 // ownerDocumentの戻り値は ?Dom\Document なので、nullチェックを行います。 58 if ($ownerDocument !== null) { 59 echo "\nownerDocumentプロパティからDocumentオブジェクトが見つかりました。\n"; 60 echo "ownerDocumentのnodeName: " . $ownerDocument->nodeName . "\n"; // ドキュメントノードの場合、通常は #document 61 62 // ownerDocumentが、最初に作成した$documentオブジェクトと同一のインスタンスであるかを確認します。 63 // 通常、ノードが属するドキュメントは、そのノードが作成された元のドキュメントと同じです。 64 if ($ownerDocument === $document) { 65 echo "ownerDocumentは、このDom\\EntityReferenceを作成した元のDom\\Documentオブジェクトと同一です。\n"; 66 } else { 67 echo "ownerDocumentは、元のDom\\Documentとは異なるインスタンスです。(このケースは通常発生しません)\n"; 68 } 69 } else { 70 echo "\nownerDocumentはnullです。(通常、Documentに属しているノードでは発生しません)\n"; 71 } 72} else { 73 echo "Dom\\EntityReferenceノードが見つかりませんでした。\n"; 74 echo "XMLの読み込みオプション(LIBXML_NOENT, LIBXML_DTDLOAD)やエンティティ名が正しいか確認してください。\n"; 75} 76
PHP 8のDom拡張に用意されているDom\EntityReference::ownerDocumentプロパティは、XMLやHTMLドキュメント内で定義されたエンティティ(例: &entity_name;)への参照を表すDom\EntityReferenceノードが、どのDom\Documentオブジェクトに属しているかを教えてくれるものです。このプロパティは引数を必要とせず、戻り値としてそのエンティティ参照が属するDom\Documentオブジェクト、または稀にnullを返します。
サンプルコードでは、DTDでエンティティを定義したXML文字列をDom\Documentオブジェクトに読み込むことで、Dom\EntityReferenceノードを作成しています。特にLIBXML_NOENTとLIBXML_DTDLOADオプションを使用することで、エンティティ参照がテキストとして展開されずに、Dom\EntityReferenceノードとして扱われるようにしています。その後、XPathを使ってドキュメント内のDom\EntityReferenceノードを見つけ出し、そのownerDocumentプロパティにアクセスします。このプロパティは、通常、そのノードが属している元のDom\Documentオブジェクトを返し、ノードがどのドキュメントの一部であるかを識別するのに役立ちます。
Dom\EntityReference::ownerDocumentプロパティは、特定のエンティティ参照ノードが属するXMLドキュメントオブジェクトを取得するために使われます。このプロパティを正しく利用し、Dom\EntityReferenceノードを生成するには、XMLの読み込み時にLIBXML_NOENTとLIBXML_DTDLOADオプションを必ず指定してください。これらのオプションがないと、エンティティ参照がテキストとして展開されてしまい、目的のDom\EntityReferenceノードがパースされません。ownerDocumentの戻り値は?Dom\Document型であり、通常はnullになりませんが、より安全なコードのためには常にnullチェックを行うことを推奨します。これにより、ノードの所属ドキュメントを明確に把握し、複数のドキュメントを扱う場面での間違いを防ぐことができます。