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

【PHP8.x】xml_set_unparsed_entity_decl_handler()関数の使い方

xml_set_unparsed_entity_decl_handler関数の使い方について、初心者にもわかりやすく解説します。

作成日: 更新日:

基本的な使い方

xml_set_unparsed_entity_decl_handler関数は、XMLパーサーが未解析エンティティ宣言に遭遇した際に呼び出すコールバック関数を設定する関数です。XML文書内でDTD(Document Type Definition)を用いて定義された未解析エンティティ(例えば画像などのバイナリデータ)の宣言を処理するために使用されます。

この関数を使用することで、XMLパーサーが未解析エンティティ宣言を検出したときに、特定の処理を行う独自の関数(ハンドラ)を登録できます。ハンドラ関数は、エンティティ名、ベース、システムID、パブリックIDといった情報を受け取り、必要に応じてこれらの情報に基づいて何らかの処理を実行できます。例えば、未解析エンティティの情報をログに記録したり、データベースに保存したり、あるいは別の処理に引き渡したりすることが可能です。

この関数は、xml_parser_create()関数で作成されたXMLパーサーリソースを第一引数に取ります。第二引数には、コールバック関数名(文字列)または無名関数(クロージャ)を指定します。コールバック関数は、パーサーリソース、エンティティ名、ベース、システムID、パブリックIDを引数として受け取る必要があります。

未解析エンティティは、XML文書の構造を記述するDTDで定義され、XMLパーサーが文書を解析する際に参照されます。xml_set_unparsed_entity_decl_handler関数を用いることで、XML文書に含まれる未解析エンティティ宣言に関する情報をプログラムで柔軟に処理できるようになります。これにより、XML文書の解析処理をより高度に制御し、特定のニーズに合わせた処理を実装することが可能となります。

構文(syntax)

1xml_set_unparsed_entity_decl_handler(XMLParser $parser, callable $handler): bool

引数(parameters)

XMLParser $parser, callable|string|null $handler

  • XMLParser $parser: XMLパーサーオブジェクトへの参照
  • callable|string|null $handler: 未解析エンティティ宣言の処理を行うコールバック関数、またはnull

戻り値(return)

true

この関数は、XMLパーサーが未解析のエンティティ宣言を検出した際に呼び出されるハンドラー関数を設定します。設定が成功した場合は true を返します。

サンプルコード

PHP XML要素ハンドラでXMLを解析する

1<?php
2
3/**
4 * SAX (Simple API for XML) パーサーを使用してXMLデータを解析し、
5 * 要素の開始と終了イベントを処理するサンプル関数です。
6 *
7 * この関数は、XMLデータを解析する際の基本的な要素ハンドリングを示します。
8 * システムエンジニアを目指す初心者の方がXMLパーシングの仕組みを理解するのに役立ちます。
9 */
10function parseXmlWithElementHandlers(): void
11{
12    // 処理対象のXMLデータ
13    $xmlData = <<<XML
14<?xml version="1.0" encoding="UTF-8"?>
15<catalog>
16    <book id="bk101">
17        <author>Gambardella, Matthew</author>
18        <title>XML Developer's Guide</title>
19        <genre>Computer</genre>
20        <price>44.95</price>
21        <publish_date>2000-10-01</publish_date>
22        <description>An in-depth look at creating applications with XML.</description>
23    </book>
24    <book id="bk102">
25        <author>Ralls, Kim</author>
26        <title>Midnight Rain</title>
27        <genre>Fantasy</genre>
28        <price>5.95</price>
29        <publish_date>2000-12-16</publish_date>
30        <description>A young man's struggle to come to grips with his sax.</description>
31    </book>
32</catalog>
33XML;
34
35    // XMLパーサーリソースを作成します。
36    // XMLParser型ヒントはPHP 8以降で利用可能です。
37    $parser = xml_parser_create();
38
39    // XMLタグ名の大文字・小文字を区別しない設定を解除します。
40    // これにより、XML内の元のタグ名(例: <catalog>)がそのままハンドラに渡されます。
41    xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
42
43    // 要素の開始タグが検出されたときに呼び出されるハンドラを設定します。
44    // PHP 7.4以降の短いクロージャ構文 (fn) を使用しています。
45    $startElementHandler = fn (XMLParser $parser, string $name, array $attributes) =>
46        print("開始: {$name}" . (!empty($attributes) ? " 属性: " . json_encode($attributes) : "") . PHP_EOL);
47
48    // 要素の終了タグが検出されたときに呼び出されるハンドラを設定します。
49    $endElementHandler = fn (XMLParser $parser, string $name) =>
50        print("終了: {$name}" . PHP_EOL);
51
52    // xml_set_element_handler関数を使用して、開始と終了のハンドラをパーサーに登録します。
53    xml_set_element_handler($parser, $startElementHandler, $endElementHandler);
54
55    // XMLデータを解析します。
56    // xml_parse関数は成功した場合に true を、失敗した場合に false を返します。
57    if (!xml_parse($parser, $xmlData, true)) { // true はこれが最後のデータブロックであることを示します
58        // 解析エラーが発生した場合、エラー情報を出力します。
59        $errorCode = xml_get_error_code($parser);
60        $errorString = xml_error_string($errorCode);
61        $line = xml_get_current_line_number($parser);
62        $column = xml_get_current_column_number($parser);
63        error_log("XML解析エラー: [{$errorCode}] {$errorString} (行: {$line}, 列: {$column})");
64    }
65
66    // パーサーリソースを解放します。
67    xml_parser_free($parser);
68}
69
70// 関数を実行してXML解析を開始します。
71parseXmlWithElementHandlers();

PHPのxml_set_element_handler関数は、SAX (Simple API for XML) パーサーでXMLデータを解析する際に、要素(タグ)の開始と終了イベントを処理するためのハンドラを設定します。この関数は、第1引数で指定されたXMLParserリソースに対し、第2引数に開始タグが検出されたときに呼び出される関数を、第3引数に終了タグが検出されたときに呼び出される関数を登録します。開始ハンドラはXMLの開始タグが検出されたときに、タグ名と属性情報を引数として受け取ります。終了ハンドラはXMLの終了タグが検出されたときに、タグ名を引数として受け取ります。サンプルコードでは、要素の開始時に「開始: タグ名」と属性を、終了時に「終了: タグ名」を画面に出力しています。xml_set_element_handlerは、ハンドラの登録に成功すると常にtrueを返します。この仕組みにより、XMLデータの構造をイベント駆動で効率的に処理できます。

このコードは、SAXパーサーでXMLの要素開始・終了イベントを処理する基本です。xml_parser_create()でパーサーを作成後、処理終了時にはxml_parser_free()で必ず解放し、リソースリークを防いでください。xml_parse()の戻り値を常に確認し、エラー発生時はxml_get_error_code()で詳細を捕捉し、適切なエラーハンドリングを行うことが堅牢なシステム開発には不可欠です。XML_OPTION_CASE_FOLDINGを0に設定することで、タグ名の大文字・小文字が元のXML通りに扱われる点に注意が必要です。PHP 7.4以降の短いクロージャやPHP 8の型ヒントも活用されています。

PHP XMLパーサで非解析実体宣言を処理する

1<?php
2
3/**
4 * XMLパーサが非解析実体宣言を見つけたときに呼び出されるハンドラ関数。
5 *
6 * この関数は、XMLドキュメントのDTD(Document Type Definition)内で
7 * `<!ENTITY entityName SYSTEM "uri" NDATA notationName>`
8 * の形式で宣言された実体(unparsed entity)が検出されたときに実行されます。
9 * 非解析実体は、XMLプロセッサがその内容を解析せず、外部アプリケーションが処理することを想定しています。
10 *
11 * @param XMLParser $parser      XMLパーサのリソース。PHP 8以降ではXMLParserオブジェクト。
12 * @param string    $entityName  宣言された実体の名前。例: "myimage"
13 * @param string    $notationName 実体に関連付けられた記法名。例: "jpeg"
14 * @param string    $publicId    実体の公開ID(存在しない場合は空文字列)。
15 * @param string    $systemId    実体のシステムID(URIまたはファイルパス)。例: "path/to/image.jpg"
16 * @return void
17 */
18function handleUnparsedEntityDeclaration(
19    XMLParser $parser,
20    string $entityName,
21    string $notationName,
22    string $publicId,
23    string $systemId
24): void {
25    echo "--- 非解析実体宣言ハンドラが呼び出されました ---\n";
26    echo "  実体名 (Entity Name): " . $entityName . "\n";
27    echo "  記法名 (Notation Name): " . $notationName . "\n";
28    echo "  公開ID (Public ID): " . ($publicId ?: "(なし)") . "\n";
29    echo "  システムID (System ID): " . $systemId . "\n";
30    echo "--------------------------------------------------\n\n";
31}
32
33// 1. XMLパーサを作成します。
34// xml_parser_create() 関数は、XMLデータを解析するための新しいパーサインスタンスを生成します。
35$parser = xml_parser_create();
36
37if (!$parser) {
38    die("XMLパーサの作成に失敗しました。\n");
39}
40
41// 2. 非解析実体宣言ハンドラを設定します。
42// xml_set_unparsed_entity_decl_handler() は、DTD内で非解析実体宣言が発見されたときに
43// どの関数を呼び出すかを指定します。
44// ここでは、定義した 'handleUnparsedEntityDeclaration' 関数が呼び出されるように設定します。
45xml_set_unparsed_entity_decl_handler($parser, 'handleUnparsedEntityDeclaration');
46
47// 3. 解析するXMLデータを準備します。
48// このXMLにはDTD(Document Type Definition)が含まれており、
49// その中で「myimage」という名前の非解析実体が宣言されています。
50// 'NDATA jpeg' は、この実体がJPEG形式の外部データであり、
51// XMLパーサ自体は内容を解析しないことを示します。
52$xmlData = <<<XML
53<?xml version="1.0" encoding="UTF-8"?>
54<!DOCTYPE root [
55  <!-- 'myimage' は "path/to/image.jpg" を指す非解析実体で、JPEG形式であると宣言しています。 -->
56  <!ENTITY myimage SYSTEM "path/to/image.jpg" NDATA jpeg>
57  <!-- 'jpeg' は "image/jpeg" MIMEタイプを持つ記法であると宣言しています。 -->
58  <!NOTATION jpeg SYSTEM "image/jpeg">
59]>
60<root>
61  <description>このXMLは非解析実体の定義を含みます。</description>
62  <!-- 注意: ここで "myimage" 実体が直接参照されているわけではありませんが、
63       上記の DTD で宣言された時点でハンドラはトリガーされます。 -->
64  <item type="product" imageUrl="myimage_placeholder" />
65</root>
66XML;
67
68echo "--- XMLデータの解析を開始します ---\n";
69
70// 4. XMLデータを解析します。
71// xml_parse() 関数は、提供されたXML文字列を解析し、設定されたハンドラを呼び出します。
72// 第3引数の 'true' は、これが解析する最後のデータチャンクであることを示します。
73$success = xml_parse($parser, $xmlData, true);
74
75if (!$success) {
76    // 解析中にエラーが発生した場合、詳細情報を表示します。
77    $errorCode = xml_get_error_code($parser);
78    $errorString = xml_error_string($errorCode);
79    $line = xml_get_current_line_number($parser);
80    $col = xml_get_current_column_number($parser);
81    echo "\n!!! XML解析エラー: {$errorString} (コード: {$errorCode}) 行: {$line}, 列: {$col} !!!\n";
82} else {
83    echo "\n--- XML解析が完了しました ---\n";
84}
85
86// 5. XMLパーサのリソースを解放します。
87// メモリリークを防ぐために、使用が終わったらパーサを解放することが推奨されます。
88xml_parser_free($parser);
89
90?>

xml_set_unparsed_entity_decl_handler関数は、XMLパーサがXML文書のDTD(文書型定義)内で「非解析実体宣言」を見つけたときに、特定の関数を呼び出すように設定するものです。非解析実体とは、XMLパーサ自身がその内容を直接解析せず、外部のアプリケーションが処理することを想定しているデータ(例えば、画像ファイルや音声ファイルなど)を指します。

この関数は、最初の引数としてxml_parser_create()で作成したXMLパーサのリソース(PHP 8ではXMLParserオブジェクト)を受け取ります。2番目の引数には、非解析実体宣言が検出されたときに呼び出される関数名を文字列で指定します。設定が成功した場合、戻り値としてtrueを返します。

サンプルコードでは、まずxml_parser_create()でXMLパーサを作成し、次にxml_set_unparsed_entity_decl_handler()を用いてhandleUnparsedEntityDeclarationという関数をハンドラとして登録しています。用意されたXMLデータには、画像のような外部ファイル「myimage」を指す非解析実体がDTD内に宣言されています。xml_parse()でこのXMLデータを解析すると、非解析実体宣言が検出された瞬間にhandleUnparsedEntityDeclarationが自動的に実行されます。このハンドラ関数は、検出された実体の名前やその関連情報(ファイルパスなど)を受け取り、それらを画面に表示します。これにより、XMLデータに外部データへの参照が含まれている場合、その情報を検知し、適切な処理を行う準備ができます。最後に、xml_parser_free()でパーサを解放しています。

このサンプルコードは、XMLのDTD内で定義された「非解析実体宣言」を検知するための処理を示しています。非解析実体とは、XMLパーサ自身がその内容を解析しない外部データであり、NDATAキーワードで指定されるため、その宣言が見つかったときにハンドラが呼び出されます。パーサの作成にはxml_parser_create関数を使い、使用後は必ずxml_parser_freeで解放し、メモリリークを防ぎましょう。また、xml_parseの実行結果は必ず確認し、エラーが発生した場合はxml_get_error_codeなどで原因を特定する習慣が大切です。このハンドラ関数は、XMLドキュメントのDTD内で実体が宣言された時点でトリガーされ、ドキュメント本文でその実体が参照されているかどうかは問いません。

関連コンテンツ

関連IT用語

関連プログラミング言語