【PHP8.x】Dom\Entity::textContentプロパティの使い方
textContentプロパティの使い方について、初心者にもわかりやすく解説します。
基本的な使い方
textContentプロパティは、PHPのDOM拡張機能におけるDom\Entityクラスに属しており、HTMLやXML文書内の特定のノード、またはそのすべての子孫ノードが持つテキストコンテンツを保持するプロパティです。これは、要素のタグ構造を除いた、純粋なテキスト情報を扱うために利用されます。
このプロパティから値を取得する場合、対象のノードに含まれるHTMLタグやXMLタグなどの構造情報を除いた、テキスト部分のみが文字列として返されます。例えば、<p>こんにちは<b>世界</b>!</p>という要素があった場合、textContentプロパティからは「こんにちは世界!」という文字列を取得できます。これにより、要素の視覚的な内容を簡単に抽出することが可能です。
一方、このプロパティに新しいテキスト値を設定することもできます。値を設定すると、対象のノードが元々持っていたすべての子ノード(テキストノード、要素ノードなど)はすべて削除され、設定されたテキスト値のみを持つ新しいテキストノードに置き換えられます。これは、プログラムから要素の内部コンテンツを、テキストのみで一括して更新したい場合に非常に役立ちます。
このプロパティを使用することで、複雑なDOM操作を行うことなく、HTMLやXML文書のテキスト内容を効率的に取得したり、変更したりすることができます。特に、ウェブスクレイピングで特定の情報のテキスト部分だけを抽出したい場合や、動的にウェブページの内容を更新したいシステム開発の場面で、その簡潔さと強力さから頻繁に活用されます。
構文(syntax)
1<?php 2 3// DTDでエンティティが定義されたXML文字列 4$xmlString = <<<XML 5<?xml version="1.0" encoding="utf-8"?> 6<!DOCTYPE root [ 7 <!ENTITY myEntity "This is the entity text."> 8]> 9<root>&myEntity;</root> 10XML; 11 12// Dom\Documentオブジェクトをインスタンス化 13$doc = new Dom\Document(); 14 15// DTDを読み込むオプションを付けてXMLをロード 16$doc->loadXML($xmlString, LIBXML_DTDLOAD); 17 18// 'myEntity'という名前のエンティティノード(Dom\Entity)を取得 19$entity = $doc->doctype->entities->getNamedItem('myEntity'); 20 21// Dom\EntityオブジェクトのtextContentプロパティ(読み取り専用)から 22// エンティティの置換テキストを取得して出力します 23echo $entity->textContent; 24 25?>
引数(parameters)
引数なし
引数はありません
戻り値(return)
string
Dom\EntityクラスのtextContentプロパティは、そのDOM要素内のすべてのテキストコンテンツを文字列として返します。これには、子要素のテキストコンテンツもすべて含まれます。
サンプルコード
PHP: DOMエンティティのtextContentを取得する
1<?php 2 3/** 4 * Dom\EntityのtextContentプロパティの使用例を示します。 5 * 6 * DTD(文書型定義)内で宣言されたエンティティのテキスト内容を取得します。 7 */ 8function showEntityTextContentExample(): void 9{ 10 // DTDでエンティティを宣言したXML文字列を定義します。 11 // <!ENTITY copyright "Copyright (C) 2023 My Company."> の部分がエンティティ宣言です。 12 $xmlString = <<<XML 13<?xml version="1.0" encoding="UTF-8"?> 14<!DOCTYPE document [ 15 <!ENTITY copyright "Copyright (C) 2023 My Company."> 16]> 17<document> 18 <footer>©right;</footer> 19</document> 20XML; 21 22 // DOMDocumentオブジェクトをインスタンス化します。 23 $doc = new DOMDocument(); 24 25 // XML文字列を読み込みます。 26 $doc->loadXML($xmlString); 27 28 // DTD(文書型定義)を表す DOMDocumentType オブジェクトを取得します。 29 $doctype = $doc->doctype; 30 31 // DTDが存在し、エンティティが定義されているか確認します。 32 if ($doctype && $doctype->entities) { 33 // 'copyright' という名前のエンティティ(Dom\Entity オブジェクト)を取得します。 34 // このオブジェクトは `<!ENTITY copyright ...>` という宣言自体を表します。 35 $entityNode = $doctype->entities->getNamedItem('copyright'); 36 37 if ($entityNode instanceof \DOMEntity) { 38 // textContentプロパティは、エンティティの置換テキストを返します。 39 // この場合、"Copyright (C) 2023 My Company." が出力されます。 40 echo $entityNode->textContent . PHP_EOL; 41 } 42 } 43} 44 45// 関数を実行して結果を表示します。 46showEntityTextContentExample();
PHPのDom\Entityクラスが持つtextContentプロパティは、XML文書のDTD(文書型定義)内で宣言されたエンティティのテキスト内容を取得するために使用します。このプロパティに引数はありません。戻り値として、エンティティの置換テキストが文字列(string)で返されます。
サンプルコードでは、まず<!ENTITY copyright "Copyright (C) 2023 My Company.">というエンティティ宣言を含むXML文字列を定義しています。この宣言は、©right;という記述を"Copyright (C) 2023 My Company."というテキストに置き換えるための定義です。
次に、DOMDocumentクラスでこのXMLを読み込み、文書の構造を解析します。続いて、doctypeプロパティからDTDの情報を、さらにその中のentitiesプロパティからエンティティの一覧を取得します。getNamedItem('copyright')メソッドを使って、copyrightエンティティを表すDOMEntityオブジェクトを取得後、そのtextContentプロパティにアクセスします。これにより、エンティティ宣言の値である"Copyright (C) 2023 My Company."という文字列が取得され、画面に出力されます。このように、textContentプロパティは、DTDで定義されたエンティティの実体となるテキストデータを抽出する際に便利なプロパティです。
Dom\EntityのtextContentプロパティは、XML本文に表示されるテキストではなく、DTD(文書型定義)内で宣言されたエンティティの「置換テキスト」そのものを取得します。この機能を使う前提として、XML内にDTDとエンティティ宣言が存在しなければなりません。DOMDocumentオブジェクトからdoctype、そしてentitiesプロパティを順に経由して目的のエンティティを取得する必要があります。DTDやエンティティが存在しない場合にエラーとなるのを防ぐため、サンプルコードのようにif文でオブジェクトの存在を必ず確認してからプロパティにアクセスすることが重要です。このプロパティは読み取り専用のため、値の取得のみ可能で、内容の書き換えはできません。
PHP DOM: nodeValue vs textContent 比較
1<?php 2 3declare(strict_types=1); 4 5/** 6 * DOMElementにおけるnodeValueとtextContentの違いを比較します。 7 * 8 * `textContent` は自身とすべての子孫ノードのテキストを連結して返します。 9 * 一方、`nodeValue` はノードの型に依存し、要素ノード(DOMElement)の場合は常にnullを返します。 10 */ 11function compareNodeValueAndTextContent(): void 12{ 13 // 比較対象となるHTML文字列を準備します。 14 // このHTMLは、テキストノード、要素ノード(strong)、コメントノードを含んでいます。 15 $html = '<div id="main">Hello <strong>World</strong><!-- comment -->!</div>'; 16 17 // DOMDocumentオブジェクトを生成し、HTMLを解析します。 18 $dom = new DOMDocument(); 19 // HTMLフラグメントとして読み込むことで、<html>や<body>タグの自動補完を防ぎます。 20 $dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); 21 22 // 'div'タグの要素を取得します。 23 $divElement = $dom->getElementsByTagName('div')->item(0); 24 25 // 要素が取得できなかった場合は終了します。 26 if ($divElement === null) { 27 echo '<div> element could not be found.' . PHP_EOL; 28 return; 29 } 30 31 // --- textContent の出力 --- 32 // textContentプロパティは、要素ノードとそのすべての子孫ノード(strongタグ内など)の 33 // テキストコンテンツを連結して取得します。HTMLタグやコメントは無視されます。 34 // 期待される出力: "Hello World!" 35 $textContent = $divElement->textContent; 36 echo 'textContent: "' . $textContent . '"' . PHP_EOL; 37 38 // --- nodeValue の出力 --- 39 // 一方、nodeValueプロパティは、要素ノード(DOMElement)に対しては常にnullを返します。 40 // nodeValueが値を持つのは、テキストノード(DOMText)やコメントノード(DOMComment)など、 41 // 特定のノードタイプの場合のみです。 42 // 期待される出力: NULL 43 $nodeValue = $divElement->nodeValue; 44 echo 'nodeValue: '; 45 var_dump($nodeValue); 46} 47 48// 関数を実行して結果を表示します。 49compareNodeValueAndTextContent();
Dom\Entityクラスに属するtextContentプロパティは、XMLやHTMLの特定の要素(ノード)と、その内部に含まれるすべての子孫要素のテキスト部分を連結して、一つの文字列として取得します。このプロパティに引数はなく、戻り値はstring型です。HTMLタグやコメントは無視され、人間が読むテキストコンテンツのみが抽出されます。
サンプルコードでは、<div>Hello <strong>World</strong><!-- comment -->!</div> というHTML構造からdiv要素を取得しています。このdiv要素のtextContentプロパティにアクセスすると、要素内のテキスト「Hello 」と「!」、そして子要素であるstrongタグ内の「World」が連結され、「Hello World!」という文字列が得られます。
比較対象としてnodeValueプロパティがありますが、これは要素ノード(DOMElement)に対して使用すると常にnullを返します。nodeValueはテキストノードやコメントノードのような、特定タイプのノードの値を取得するためのものです。そのため、要素が内包する表示テキスト全体を取得したい場合には、textContentプロパティを使用するのが適切です。
要素ノードからテキストを取得する際は textContent を使用します。このプロパティは、指定した要素だけでなく、その中に含まれる全ての子孫要素のテキストを連結して一つの文字列として返してくれるため便利です。HTMLタグやコメントは自動的に除外されます。一方、nodeValue は要素ノードに対して使用すると常に null を返します。nodeValue が値を持つのはテキストノードやコメントノードなどを直接扱う場合に限られるため、要素内のテキスト取得には不向きです。この違いから、HTMLタグ内の表示テキストを取得したい場合は textContent を使うのが正しい方法です。また、getElementsByTagName などで要素を取得する際は、対象が見つからず null が返る可能性があるため、必ず存在チェックを行いましょう。