【PHP8.x】Dom\DocumentType::entitiesプロパティの使い方
entitiesプロパティの使い方について、初心者にもわかりやすく解説します。
基本的な使い方
entitiesプロパティは、Dom\DocumentTypeクラスに属し、ドキュメント型定義(DTD)内で宣言されている一般エンティティの定義情報を保持するプロパティです。
Dom\DocumentTypeクラスは、HTMLやXMLドキュメントのDOCTYPE宣言、つまりドキュメントの構造や使用できる要素、属性、そしてエンティティなどのルールを定義した部分を表します。エンティティとは、例えば著作権記号のような特殊文字や、繰り返し使用される長い文字列などを短い名前で参照できるようにする仕組みのことです。
このentitiesプロパティは、DOCTYPE宣言内で定義されているこれらのエンティティのリストをDom\NamedNodeMapオブジェクトとして提供します。Dom\NamedNodeMapは、名前でアクセスできるノードの集合を扱うためのインターフェースです。個々のエンティティ定義は、その名前を使ってこのMapから取得することができます。
重要な点として、このプロパティはドキュメント内で実際に参照されたエンティティ(例えば「©」)が展開された結果ではなく、あくまでDTD自体に記述された「エンティティの定義情報」そのものの集合を保持しています。そのため、このプロパティは、DOM拡張機能を利用してドキュメントのDTDをプログラムで解析し、どのようなエンティティが定義されているかを確認したり、ドキュメントの構造を深く理解したりする際に役立ちます。システムエンジニアにとって、XMLやHTMLのスキーマを理解し、バリデーションや変換処理を行う上で、このようなDTDのメタデータにアクセスできることは非常に重要です。
構文(syntax)
1<?php 2 3$xml = <<<XML 4<?xml version="1.0" encoding="UTF-8"?> 5<!DOCTYPE root [ 6 <!ENTITY company "Example Corp."> 7 <!ENTITY year "2023"> 8]> 9<root> 10 <item>Document by &company; in &year;.</item> 11</root> 12XML; 13 14$dom = new DOMDocument(); 15$dom->loadXML($xml); 16 17$doctype = $dom->doctype; 18 19if ($doctype instanceof DOMDocumentType) { 20 $entities = $doctype->entities; 21 22 if ($entities) { 23 foreach ($entities as $entity) { 24 echo "Entity Name: " . $entity->nodeName . ", Value: " . $entity->nodeValue . "\n"; 25 } 26 } 27} 28 29?>
引数(parameters)
引数なし
引数はありません
戻り値(return)
DOMNamedNodeMap
Dom\DocumentType クラスの entities プロパティは、その文書型宣言で宣言されているエンティティのコレクションを表す DOMNamedNodeMap オブジェクトを返します。このマップには、エンティティ名がキーとして、各エンティティを表す DOMEntity オブジェクトが値として格納されています。
サンプルコード
DTDエンティティ定義情報を取得する
1<?php 2 3/** 4 * Dom\DocumentType::entities プロパティを使用して、 5 * DTD (Document Type Definition) に定義されたエンティティの情報を取得し表示します。 6 * 7 * この機能は、XMLまたはSGMLドキュメントのDOCTYPE宣言に明示的に定義された 8 * エンティティ(実体参照)のリストを取得するために使用されます。 9 * HTML文字列内の一般的な数値/名前付きエンティティ(例: &, <, )を 10 * その文字自体に変換する `html_entity_decode()` や `htmlspecialchars_decode()` 関数とは 11 * 目的が異なります。それらの関数は、DTDの定義とは独立して、HTML仕様に組み込まれた 12 * 既知のエンティティや文字参照を処理します。 13 * 14 * このサンプルコードでは、DTDにカスタムエンティティを定義したXMLドキュメントを扱い、 15 * そのエンティティがどのようにリストされるかを示します。 16 */ 17function showDocumentTypeEntitiesExample(): void 18{ 19 // DTD (Document Type Definition) でエンティティを定義したXML文字列を用意します。 20 // 'customEntity' は内部一般エンティティ、'copyright' は数値文字参照の例です。 21 // 'externalEntity' は外部一般エンティティの例で、systemId を持ちます。 22 $xmlString = <<<XML 23<!DOCTYPE root [ 24 <!ENTITY customEntity "Hello, DTD Entity!"> 25 <!ENTITY copyright "©"> <!-- Unicode © は © を表します --> 26 <!ENTITY externalEntity SYSTEM "http://example.com/some_data.xml"> 27]> 28<root> 29 <item>&customEntity;</item> 30 <item>©right;</item> 31 <item>&externalEntity;</item> 32</root> 33XML; 34 35 // DOMDocument オブジェクトを作成し、XML文字列をロードします。 36 // LIBXML_NONET フラグは、DTDに含まれる外部リソースへのネットワークアクセスを防止します。 37 $dom = new DOMDocument(); 38 // 外部エンティティを解決しようとすると警告が出ることがあるため、エラーを抑制します。 39 @$dom->loadXML($xmlString, LIBXML_NONET); 40 41 // Dom\DocumentType オブジェクトを取得します。 42 // ドキュメントにDOCTYPE宣言がない場合、nullが返されます。 43 $documentType = $dom->doctype; 44 45 if ($documentType === null) { 46 echo "エラー: ドキュメントに DOCTYPE 宣言が見つかりませんでした。\n"; 47 return; 48 } 49 50 echo "--- ドキュメントタイプ情報 ---\n"; 51 echo "DOCTYPE名: " . $documentType->name . "\n"; 52 echo "公開識別子 (Public ID): " . ($documentType->publicId ?: 'なし') . "\n"; 53 echo "システム識別子 (System ID): " . ($documentType->systemId ?: 'なし') . "\n"; 54 echo "\n"; 55 56 // Dom\DocumentType::entities プロパティにアクセスします。 57 // これは DOMNamedNodeMap オブジェクトを返し、DTDに定義されたエンティティ(DOMEntityオブジェクト)の 58 // リストを含みます。 59 $entities = $documentType->entities; 60 61 if ($entities->length === 0) { 62 echo "DOCTYPE 宣言内にエンティティの定義が見つかりませんでした。\n"; 63 } else { 64 echo "--- 定義されているエンティティのリスト ---\n"; 65 /** @var DOMEntity $entity */ 66 foreach ($entities as $entity) { 67 echo " エンティティ名 (nodeName): " . $entity->nodeName . "\n"; 68 // 内部一般エンティティの場合、nodeValue にその「実体」が格納されます。 69 // 外部エンティティや未解析エンティティの場合、nodeValue は空の場合が多いです。 70 echo " 値 (nodeValue): " . ($entity->nodeValue ?: '[値なしまたは外部エンティティ]') . "\n"; 71 echo " 公開識別子 (Public ID): " . ($entity->publicId ?: 'なし') . "\n"; 72 echo " システム識別子 (System ID): " . ($entity->systemId ?: 'なし') . "\n"; 73 echo " 表記法名 (NotationName): " . ($entity->notationName ?: 'なし') . "\n"; 74 echo " --------------------\n"; 75 } 76 } 77 78 echo "\n--- 補足情報 ---\n"; 79 echo "この `Dom\DocumentType::entities` は、DTDで定義されたエンティティの『定義情報』を\n"; 80 echo "取得するものです。HTML文字列中の `&` や `<` などの文字参照を\n"; 81 echo "実際の文字 (`&`, `<`) に変換する『デコード』とは異なります。\n"; 82 echo "XML/HTMLパーサーは、これらのエンティティ定義に基づいて、ドキュメント内の\n"; 83 echo "エンティティ参照(例: `&customEntity;`)をその実体(`Hello, DTD Entity!`)に\n"; 84 echo "置き換える(展開する)処理を行います。\n"; 85} 86 87// サンプル関数を実行します。 88showDocumentTypeEntitiesExample(); 89 90?>
Dom\DocumentType::entitiesプロパティは、PHP 8で導入されたDOM拡張機能の一部で、XMLやSGMLドキュメントのDOCTYPE宣言に定義されているエンティティ(実体参照)の情報を取得するために使用されます。このプロパティはDom\DocumentTypeクラスに属し、引数はありません。アクセスすると、DTDに定義されたエンティティをDOMEntityオブジェクトとして格納するDOMNamedNodeMapオブジェクトを返します。
取得されるDOMNamedNodeMapには、<!ENTITY ...>構文で定義されたエンティティの「名前」「値(実体)」「公開識別子」「システム識別子」などの詳細情報が含まれています。これにより、ドキュメントにどのようなカスタムエンティティが定義されているかをプログラムで把握できます。
このプロパティは、HTML文字列中の&や<といった一般的な数値・名前付きエンティティを&や<などの実際の文字に変換するhtml_entity_decode()やhtmlspecialchars_decode()関数とは目的が異なります。Dom\DocumentType::entitiesは、ドキュメントのDTD内で定義されたエンティティの「定義そのもの」をリストアップするものであり、HTMLのエンティティ参照を文字に「デコード」する機能ではありません。主に、XMLドキュメントの構造や利用されるエンティティの定義をプログラムで解析する際に役立ちます。
Dom\DocumentType::entitiesプロパティは、XMLやSGMLドキュメントのDTD(Document Type Definition)に定義されたエンティティの『定義情報』を取得するために使われます。これは、HTML文字列中の&や<などの『文字参照』を実際の文字に変換するhtml_entity_decode()関数やhtmlspecialchars_decode()関数とは全く異なる目的を持ちます。このプロパティは、DTDで定義されたカスタムエンティティの構造や属性(値、Public ID、System IDなど)を知りたい場合に利用します。一般的なHTMLページの解析やエンティティのデコードには適していませんので注意が必要です。ドキュメントにDOCTYPE宣言がない場合やエンティティ定義がない場合は、空のリストが返されますので、nullチェックと同様に返されるリストの長さも確認してください。
PHPでXML DTDエンティティを取得する
1<?php 2 3/** 4 * XMLドキュメントからDTDエンティティの定義を取得し、その情報を表示します。 5 * 6 * この関数は、XMLのDTD(Document Type Definition)で定義されたカスタムエンティティが、 7 * ドキュメント内でどのように「符号化」または「表現」されるか(エンティティ名とその実体値)を示します。 8 * 「php entities encode」というキーワードに関連して、エンティティの定義内容が 9 * 実際にXML内で何に「エンコード」(置き換え)されるかを示しています。 10 * システムエンジニアを目指す初心者の方でも、DTDエンティティの概念と、 11 * それをPHPでプログラムからどう扱うかを理解しやすいように設計されています。 12 * 13 * @param string $xmlString DTDを含むXML文字列。 14 * @return void 15 */ 16function displayXmlEntities(string $xmlString): void 17{ 18 // DOMDocumentオブジェクトを作成します。 19 // これはXMLパーサーとして機能し、XMLドキュメントの構造を操作するための基盤となります。 20 $dom = new Dom\DOMDocument(); 21 // 厳密なエラーチェックを有効にし、XMLの構文解析時に問題があれば通知するようにします。 22 $dom->validateOnParse = true; 23 24 // 提供されたXML文字列をDOMDocumentにロードします。 25 // loadXML()メソッドは、文字列からXMLドキュメントを解析します。 26 // このプロセスで、XML内に定義されたDTDエンティティも読み込まれます。 27 $dom->loadXML($xmlString); 28 29 // ドキュメントタイプノードを取得します。 30 // XMLドキュメントのDTD情報(エンティティ定義など)がこのオブジェクトに含まれています。 31 $documentType = $dom->doctype; 32 33 // ドキュメントタイプノードが存在する場合のみ処理を進めます。 34 // DTDが定義されていないXMLやHTMLドキュメントでは、$documentType は null になります。 35 if ($documentType instanceof Dom\DocumentType) { 36 echo "--- DTDエンティティのリスト ---\n"; 37 38 // Dom\DocumentType::entities プロパティは、DTDで定義されたエンティティの 39 // DOMNamedNodeMap(名前でアクセス可能なノードのコレクション)を返します。 40 // ここには、各エンティティがどのような値に「エンコード」(置き換え)されるかの 41 // 定義がコレクションとして含まれています。 42 $entities = $documentType->entities; 43 44 // エンティティが1つ以上定義されているか確認します。 45 if ($entities->length > 0) { 46 // 各エンティティノードをループして情報を表示します。 47 foreach ($entities as $entity) { 48 /** @var Dom\DOMEntity $entity */ // 型ヒント:$entityがDom\DOMEntityであることを示します 49 echo " エンティティ名: " . $entity->nodeName . "\n"; 50 // nodeValue は、そのエンティティがXMLドキュメント内で参照された場合に、 51 // 実際に展開される文字列(「実体値」)を示します。 52 // これは、エンティティが何に「エンコード」されているかを示していると言えます。 53 echo " 実体値 (エンコードされた内容): " . $entity->nodeValue . "\n"; 54 echo "\n"; 55 } 56 } else { 57 echo " このドキュメントタイプにはエンティティ定義が見つかりませんでした。\n"; 58 } 59 } else { 60 echo "ドキュメントタイプノードが見つかりませんでした。\n"; 61 echo "XMLにDTD(Document Type Definition)が定義されていない可能性があります。\n"; 62 } 63} 64 65// -------------------------------------------------------------------------- 66// サンプルコードの実行例 67// -------------------------------------------------------------------------- 68 69// DTD内部サブセットでカスタムエンティティを定義したXML文字列の例。 70// <!DOCTYPE document [...]> の部分で 'greeting', 'company', 'copyright' という 71// 3つのエンティティが定義されています。 72$sampleXmlWithEntities = <<<XML 73<!DOCTYPE document [ 74 <!ENTITY greeting "Hello, World!"> 75 <!ENTITY company "Example Corp."> 76 <!ENTITY copyright "Copyright © 2023."> 77]> 78<document> 79 <message>&greeting;</message> 80 <info>Manufactured by &company;.</info> 81 <footer>©right;</footer> 82</document> 83XML; 84 85// 上記のXML文字列を解析し、DTDエンティティの情報を表示します。 86displayXmlEntities($sampleXmlWithEntities); 87 88?>
このPHPサンプルコードは、XMLドキュメント内に定義されたDTD(Document Type Definition)エンティティの情報を取得し、表示する方法を示しています。エンティティとは、XML内で特定の名前を定義し、それを別の文字列(実体値)に「エンコード」(置き換え)する仕組みです。これにより、共通のテキストや特殊文字を簡潔に表現できます。
コードの中心となるのは、Dom\DocumentTypeクラスのentitiesプロパティです。このプロパティは、DTDで定義されたすべてのエンティティのコレクションをDOMNamedNodeMapとして返します。このコレクションに含まれる各エンティティは、エンティティ名(nodeName)と、それが実際にXML内で何に「エンコード」(置き換え)されるかを示す実体値(nodeValue)を持っています。
displayXmlEntities関数は、DTDを含むXML文字列を引数($xmlString)として受け取ります。関数内部では、まずDom\DOMDocumentオブジェクトにXMLをロードし、$dom->doctypeプロパティでドキュメントタイプ情報を取得します。次に、$documentType->entitiesプロパティを用いてエンティティのコレクションを取得し、その中をループして各エンティティの名前と実体値を画面に出力します。この関数自体は情報を表示するのみで、特定の値を返しません(void)。Dom\DocumentType::entitiesプロパティは引数を取らず、DOMNamedNodeMapを戻り値として返します。これにより、プログラムからXMLのDTDエンティティ定義を正確に把握し、利用することが可能となります。
Dom\DocumentType::entitiesプロパティを利用するには、解析対象のXMLにDTD(Document Type Definition)が明確に定義されている必要があります。DTDが存在しないXMLでは、$dom->doctypeがnullとなるため、必ずプロパティにアクセスする前にnullチェックまたはinstanceofで型の確認を行ってください。このプロパティは、DTD内で定義されたエンティティのコレクションであるDOMNamedNodeMapを返します。ここから各エンティティのnodeName(エンティティ名)とnodeValue(実体値)を取得することで、エンティティがXML内で何に「エンコード」(置き換え)されるかを確認できます。外部から提供されるXMLを解析する際には、XML外部エンティティ(XEE)攻撃などのセキュリティリスクを考慮し、libxml_disable_entity_loader(true)のような対策を検討することが重要です。このプロパティはDTDエンティティの定義取得に特化しており、HTMLの特殊文字参照とは扱いが異なります。
PHPでHTMLエンティティをデコードする
1<?php 2 3/** 4 * HTMLエンティティを通常の文字に変換(デコード)します。 5 * 6 * この関数は、HTMLエンティティ(例: & -> &, < -> <)を含む文字列を受け取り、 7 * それらを対応する文字に変換して返します。 8 * これは、Webサイトなどから取得したコンテンツを安全に表示したり、 9 * 処理したりする前によく使用される処理です。 10 * 11 * @param string $htmlString デコードするHTMLエンティティを含む文字列。 12 * @return string デコードされた文字列。 13 */ 14function removeHtmlEntities(string $htmlString): string 15{ 16 // html_entity_decode() 関数を使用してHTMLエンティティをデコードします。 17 // ENT_QUOTES: シングルクォートとダブルクォートの両方を変換します。 18 // ENT_HTML5: HTML5ドキュメントタイプに対するエンティティを処理します。 19 // 'UTF-8': 文字エンコーディングを指定します。 20 return html_entity_decode($htmlString, ENT_QUOTES | ENT_HTML5, 'UTF-8'); 21} 22 23// サンプルコード 24 25// HTMLエンティティを含む文字列の例 26$encodedString1 = "これは<b>強調</b>されたテキストで、& と © の記号も含まれます。"; 27echo "元の文字列 1: " . $encodedString1 . PHP_EOL; 28 29// 関数を呼び出してHTMLエンティティをデコード 30$decodedString1 = removeHtmlEntities($encodedString1); 31echo "デコード後の文字列 1: " . $decodedString1 . PHP_EOL; 32 33echo PHP_EOL; // 区切り 34 35// 別のHTMLエンティティを含む文字列の例 36$encodedString2 = "URLは株式会社"Example".com です。"; 37echo "元の文字列 2: " . $encodedString2 . PHP_EOL; 38 39// 関数を呼び出してHTMLエンティティをデコード 40$decodedString2 = removeHtmlEntities($encodedString2); 41echo "デコード後の文字列 2: " . $decodedString2 . PHP_EOL; 42 43?>
このサンプルコードは、ウェブコンテンツで頻繁に利用される「HTMLエンティティ」を、通常の文字に変換(デコード)する方法をPHPで実装したものです。HTMLエンティティとは、例えば<を<、&を&のように、HTMLの構文と衝突しないように特殊な文字を表現する記号です。これにより、ブラウザで正しく表示されたり、テキストデータとして安全に扱えるようになります。
removeHtmlEntities関数は、デコードしたいHTMLエンティティを含む文字列を引数($htmlString)として受け取ります。そして、PHP標準のhtml_entity_decode関数を用いて、その文字列中のHTMLエンティティを対応する通常の文字に変換し、結果として変換済みの新しい文字列を戻り値として返します。html_entity_decode関数には、変換の挙動を詳細に指定するためのオプションが渡されています。ENT_QUOTESはシングルクォートやダブルクォートのエンティティも変換対象に含めることを意味し、ENT_HTML5はHTML5の標準に沿ってエンティティを処理するよう指定しています。さらに、文字エンコーディングとしてUTF-8を指定することで、多種多様な文字が正確に処理されます。
このような変換処理は、ウェブサイトから取得したテキストデータを安全に表示したり、データベースに保存する前処理として、あるいは他のシステムへデータ連携する際などに非常に役立ちます。この関数は、HTMLコンテンツを扱うシステム開発において、データの整合性を保ちながら扱うための基本的な処理の一つです。
提供されたリファレンスのDom\DocumentType::entitiesプロパティは、DTD内のエンティティ宣言を扱うもので、本サンプルコードのhtml_entity_decode関数とは用途が異なります。サンプルコードは、文字列中のHTMLエンティティを通常の文字へデコードする際に利用されます。html_entity_decodeを使用する際は、入力文字列の文字エンコーディング(例: UTF-8)を正しく指定することが重要です。指定が誤っていると文字化けの原因となります。また、ENT_QUOTESやENT_HTML5などのフラグによりデコード対象範囲が変わる点にご注意ください。デコード後の文字列をそのままWebページに表示すると、XSSなどのセキュリティリスクが生じる可能性があるため、表示前に必ず適切なエスケープ処理を行ってください。