XML (eXtensible Markup Language) は、Web における構造化された ドキュメント交換用のデータフォーマットです。 XML は、World Wide Web consortium (W3C) で規定された規格です。 XML に関する情報および関連する技術は、 http://www.w3.org/XML/ で参照することができます。
この拡張機能は、expat を使用します。これは、 http://www.jclark.com/xml/ にあります。 expat に付属の Makefile は、デフォルトでライブラリを構築しません。 これを行う make ルールを次のように指定できます。
libexpat.a: $(OBJS) ar -rc $@ $(OBJS) ranlib $@expat のソース RPM パッケージが http://www.guardian.no/~ssb/phpxml.html にあります。
Apache-1.3.7 以降を使用している場合、すでに必要な expat ライブラリをそろっています。 (追加パスを設定せずに) --with-xml を付けてPHP を設定する必要があります。 自動的に expat ライブラリを Apache に組み込む場合、自動的に 使用されます。
UNIX では、--with-xmlオプション を付けて configure を実行して下さい。 expat ライブラリをコンパイラのパスが通った 場所にインストールする必要があります。Apache 1.3.9 以降のモジュール として PHP をコンパイルする場合、PHP は自動的に Apache にバンドルされた expat ライブラリを使用します。 expat を通常と異なる場所にインストールした場合は、configure を実行する前に 環境変数に CPPFLAGS および LDFLAGS を設定する必要があるかもしれません。
PHP を構築して下さい。Tada! 再構築は、当然必要です。
この PHP 拡張機能は、implements support for James Clark の expat のサポートを PHP に付加します。 このツールキットは、XML ドキュメントの構文解析をしますが、 検証は行いません。 PHP でも提供される 文字エンコード法 に関して次の 3 種類のソースがサポートされます。: US-ASCII, ISO-8859-1 ,UTF-8 UTF-16 はサポートされません。
この拡張機能は、XML パーサの作成 を行い、異なった XML イベントに関して ハンドラ を定義します。 各 XML パーサーには、調整可能な小数の パラメータ もあります。
XML イベントハンドラは次のように定義されます。
表 1. サポートされる XML ハンドラ
ハンドラ設定用の PHP 関数 | イベントの説明 |
---|---|
xml_set_element_handler | 要素イベントは、XML パーサーが開始または終了タグに 出会うたびに発行されます。 開始タグと終了タグについて別のハンドラがあります。 |
xml_set_character_data_handler | 文字データは、タグの間の空白を含めて XML ドキュメントにおける ほぼ全ての非マークアップ部分の内容です。 XML パーサーは、空白を加えたり削除したりしないことに 注意して下さい。 空白が意味を有するかどうかを決めるのは、アプリケーション側の 責任です。 |
xml_set_processing_instruction_handler | PHP プログラマは、既に処理用命令 (PI) に既に 慣れているに違いありません。 <?php ?> は処理用命令であり、この場合、 php は "PI ターゲット" と呼ばれます。 これらの処理はアプリケーション依存ですが、 全ての PI ターゲットが "XML" から始まることだけは、 規定されています。 |
xml_set_default_handler | 別のハンドラでしないことをデフォルトのハンドラで行います。 XML およびドキュメント型の宣言のようなことをデフォルトハンドラで 行います。 |
xml_set_unparsed_entity_decl_handler | このハンドラは、処理されない (NDATA) エンティティの宣言用にコールされます。 |
xml_set_notation_decl_handler | このハンドラは、表記の宣言用にコールされます。 |
xml_set_external_entity_ref_handler | このハンドラは、XML パーサーが外部処理された通常のエンティティ への参照を見つけた際にコールされます。 これは、例えば、ファイルまたは URL への参照とすることが可能です。 例としては、外部エンティティの例 を参照下さい。 |
要素ハンドラ関数は、その要素に case-folded の名前をつけることができます。 大文字変換(case-folding) は、 XML 標準により "大文字でないものは等価な大文字に置換される 一連の文字に適用されるプロセス" として定義されています。 言葉を変えて言うと、XML に関しては、単に 大文字変換は大文字にすることを意味します。
デフォルトで、ハンドラ関数に渡される全ての要素名は、大文字変換されます。 この動作は、 xml_parser_get_option および xml_parser_set_option 関数で XML パーサー毎にそれぞれ問い合わせ、制御することが可能です。
(xml_parse により返されるものとして) XML エラーコードとして次のような定数が定義されています。:
XML_ERROR_NONE |
XML_ERROR_NO_MEMORY |
XML_ERROR_SYNTAX |
XML_ERROR_NO_ELEMENTS |
XML_ERROR_INVALID_TOKEN |
XML_ERROR_UNCLOSED_TOKEN |
XML_ERROR_PARTIAL_CHAR |
XML_ERROR_TAG_MISMATCH |
XML_ERROR_DUPLICATE_ATTRIBUTE |
XML_ERROR_JUNK_AFTER_DOC_ELEMENT |
XML_ERROR_PARAM_ENTITY_REF |
XML_ERROR_UNDEFINED_ENTITY |
XML_ERROR_RECURSIVE_ENTITY_REF |
XML_ERROR_ASYNC_ENTITY |
XML_ERROR_BAD_CHAR_REF |
XML_ERROR_BINARY_ENTITY_REF |
XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF |
XML_ERROR_MISPLACED_XML_PI |
XML_ERROR_UNKNOWN_ENCODING |
XML_ERROR_INCORRECT_ENCODING |
XML_ERROR_UNCLOSED_CDATA_SECTION |
XML_ERROR_EXTERNAL_ENTITY_HANDLING |
PHP の XML 拡張機能は、 異なった 文字エンコード法 の間で Unicode 文字セットを サポートします。 ソースエンコード および ターゲットエンコード という2種類の文字エンコード法があります。 PHP におけるドキュメントの内部表現は、常に UTF-8 でエンコードされます。
ソースエンコードは、XML ドキュメントが 構文解析された際に行われます。 XML パーサの作成を行う 際に、ソースエンコードを指定することができます。 (このエンコード法は、その XML パーサーが存在する間、後で変更することは できません) サポートされるソースエンコード法は、 ISO-8859-1, US-ASCII , UTF-8 です。 前の二つは、シングルバイトエンコード法です。 これは、各文字がシングルバイトで表現されることを意味します。 UTF-8 は、1 から`4 バイトの可変ビット数 (最大21 ビット) で構成された文字をエンコードすることが可能です。 PHP で用いられるデフォルトのソースエンコード法は、 ISO-8859-1 です。
ターゲットエンコード法は、PHP がデータをXML ハンドラ関数に 渡す時に行われます。 ある XML パーサが作成された際、ターゲットエンコード法は、 ソースエンコード法と同様に設定されます。 しかし、これは、いつでも変更可能です。 ターゲットエンコード法は、タグ名と同様に文字データに作用し、 命令を処理します。
XML パーサがソースエンコード法が表現できる範囲の外側で文字に 出会った場合、エラーが返されます。
解釈する XML ドキュメントにおいて PHP が文字に出会った場合、選択したターゲットエンコード法で 表現できない文字に出会った場合、問題の文字は "降格" されます。 現在、このことはこのような文字が疑問符で置換されることを 意味します。
以下に XML ドキュメントを祖よりする PHP スクリプトの例をいくつか示します。
この最初の例は、あるインデント付きのドキュメント中の start エレメントの構造を表示します。
例 1. XML エレメント構造を表示
$file = "data.xml"; $depth = array(); function startElement($parser, $name, $attrs){ global $depth; for ($i = 0; $i < $depth[$parser]; $i++) { print " "; } print "$name\n"; $depth[$parser]++; } function endElement($parser, $name){ global $depth; $depth[$parser]--; } $xml_parser = xml_parser_create(); xml_set_element_handler($xml_parser, "startElement", "endElement"); if (!($fp = fopen($file, "r"))) { die("could not open XML input"); } while ($data = fread($fp, 4096)) { if (!xml_parse($xml_parser, $data, feof($fp))) { die(sprintf("XML error: %s at line %d", xml_error_string(xml_get_error_code($xml_parser)), xml_get_current_line_number($xml_parser))); } } xml_parser_free($xml_parser);
例 2. XML を HTML にマップする
この例は、XML ドキュメントのタグを直接 HTML タグにマップします。 "map array" にないエレメントは無視されます。もちろん、 この例は、特定の XML ドキュメント型を有する場合のみ動作します。
$file = "data.xml"; $map_array = array( "BOLD" => "B", "EMPHASIS" => "I", "LITERAL" => "TT" ); function startElement($parser, $name, $attrs){ global $map_array; if ($htmltag = $map_array[$name]) { print "<$htmltag>"; } } function endElement($parser, $name){ global $map_array; if ($htmltag = $map_array[$name]) { print "</$htmltag>"; } } function characterData($parser, $data){ print $data; } $xml_parser = xml_parser_create(); // $map_array の中のタグをみつけられるように大文字変換を行う xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, true); xml_set_element_handler($xml_parser, "startElement", "endElement"); xml_set_character_data_handler($xml_parser, "characterData"); if (!($fp = fopen($file, "r"))) { die("could not open XML input"); } while ($data = fread($fp, 4096)) { if (!xml_parse($xml_parser, $data, feof($fp))) { die(sprintf("XML error: %s at line %d", xml_error_string(xml_get_error_code($xml_parser)), xml_get_current_line_number($xml_parser))); } } xml_parser_free($xml_parser);
この例は、XML コードに焦点を当てます。 この例は、他のドキュメントをインクルードし処理するための 外部エンティティリファレンスのハンドラの使用法および PI の処理方法、PI が含むコードに関する "信頼度" を定義する 手段を説明します。
この例で使用される XML ドキュメントは、例題ファイル (xmltest.xml および xmltest2.xml) にあります。
例 3. 外部エンティティの例
$file = "xmltest.xml"; function trustedFile($file){ // 自己所有のローカルファイルのみを信頼する if (!eregi("^([a-z]+)://", $file) && fileowner($file) == getmyuid()) { return true; } return false; } function startElement($parser, $name, $attribs){ print "<<font color=\"#0000cc\">$name</font>"; if (sizeof($attribs)) { while (list($k, $v) = each($attribs)) { print " <font color=\"#009900\">$k</font>=\"<font color=\"#990000\">$v</font>\""; } } print ">"; } function endElement($parser, $name){ print "</<font color=\"#0000cc\">$name</font>>"; } function characterData($parser, $data){ print "<b>$data</b>"; } function PIHandler($parser, $target, $data){ switch (strtolower($target)) { case "php": global $parser_file; // 処理されるドキュメントが "信頼されている" 場合、 // PHP コードをその内部で実行します。 // そうでない場合、そのコードが代わりに表示されます。 if (trustedFile($parser_file[$parser])) { eval($data); } else { printf("Untrusted PHP code: <i>%s</i>", htmlspecialchars($data)); } break; } } function defaultHandler($parser, $data){ if (substr($data, 0, 1) == "&" && substr($data, -1, 1) == ";") { printf('<font color="#aa00aa">%s</font>', htmlspecialchars($data)); } else { printf('<font size="-1">%s</font>', htmlspecialchars($data)); } } function externalEntityRefHandler($parser, $openEntityNames, $base, $systemId, $publicId){ if ($systemId) { if (!list($parser, $fp) = new_xml_parser($systemId)) { printf("Could not open entity %s at %s\n", $openEntityNames, $systemId); return false; } while ($data = fread($fp, 4096)) { if (!xml_parse($parser, $data, feof($fp))) { printf("XML error: %s at line %d while parsing entity %s\n", xml_error_string(xml_get_error_code($parser)), xml_get_current_line_number($parser), $openEntityNames); xml_parser_free($parser); return false; } } xml_parser_free($parser); return true; } return false; } function new_xml_parser($file) { global $parser_file; $xml_parser = xml_parser_create(); xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, 1); xml_set_element_handler($xml_parser, "startElement", "endElement"); xml_set_character_data_handler($xml_parser, "characterData"); xml_set_processing_instruction_handler($xml_parser, "PIHandler"); xml_set_default_handler($xml_parser, "defaultHandler"); xml_set_external_entity_ref_handler($xml_parser, "externalEntityRefHandler"); if (!($fp = @fopen($file, "r"))) { return false; } if (!is_array($parser_file)) { settype($parser_file, "array"); } $parser_file[$xml_parser] = $file; return array($xml_parser, $fp); } if (!(list($xml_parser, $fp) = new_xml_parser($file))) { die("could not open XML input"); } print "<pre>"; while ($data = fread($fp, 4096)) { if (!xml_parse($xml_parser, $data, feof($fp))) { die(sprintf("XML error: %s at line %d\n", xml_error_string(xml_get_error_code($xml_parser)), xml_get_current_line_number($xml_parser))); } } print "</pre>"; print "parse complete\n"; xml_parser_free($xml_parser); ?>
例 4. xmltest.xml
<?xml version='1.0'?> <!DOCTYPE chapter SYSTEM "/just/a/test.dtd" [ <!ENTITY plainEntity "FOO entity"> <!ENTITY systemEntity SYSTEM "xmltest2.xml"> ]> <chapter> <TITLE>Title &plainEntity;</TITLE> <para> <informaltable> <tgroup cols="3"> <tbody> <row><entry>a1</entry><entry morerows="1">b1</entry><entry>c1</entry></row> <row><entry>a2</entry><entry>c2</entry></row> <row><entry>a3</entry><entry>b3</entry><entry>c3</entry></row> </tbody> </tgroup> </informaltable> </para> &systemEntity; <sect1 id="about"> <title>About this Document</title> <para> <!-- this is a comment --> <?php print 'Hi! This is PHP version '.phpversion(); ?> </para> </sect1> </chapter>
This file is included from xmltest.xml:
例 5. xmltest2.xml
<?xml version="1.0"?> <!DOCTYPE foo [ <!ENTITY testEnt "test entity"> ]> <foo> <element attrib="value"/> &testEnt; <?php print "This is some more PHP code being executed."; ?> </foo>