  | 
 CXVI. XML 语法解析函数库介绍
	 XML(eXtensible Markup Language,可扩展标记语言)是一种在 WEB 上进行文档交换的数据格式。该语言是由 W3C(World Wide Web Concortium,世界万维网组织)定义的一种标准。您可以访问 http://www.w3.org/XML/ 以获取关于 XML 及其相关技术的更多信息。
     
	 本扩展模块可为 James Clark 的 expat 提供支持。该工具包帮助您解析 XML 文档(而非 XML 文档的有效化)。它支持三种源代码的编码方式,这三种编码方式也被 PHP 本身所支持,它们分别是:US-ASCII、ISO-8859-1 和 UTF-8。
     该系统尚不支持 UTF-16。
     
	 该扩展模块使您能够建立 XML 语法解析器,并对不同的 XML 事件定义对应的处理器。每个 XML 语法解析器都有若干个您可以根据需要调整的参数。
     安装
  这些函数默认为有效的,它们使用了捆绑的 expat 库。您可以通过参数 --disable-xml 来屏蔽 XML 的支持。如果您将 PHP 编译为 Apache 1.3.9 或更高版本的一个模块, PHP 将自动使用 Apache 捆绑的 expat 库。如果您不希望使用该捆绑的 expat 库,请在运行 PHP 的 configure 配置脚本时使用参数 --with-expat-dir=DIR,其中 DIR 应该指向 expat 安装的根目录。
   PHP 的 Windows 版本已经内置该扩展模块的支持。您无需加载任何附加的扩展库即可使用这些函数。 预定义常量
由于这些常量是由该扩展模块定义的,因此只有在该扩展模块被编译到 PHP 中,或者在运行时被动态加载后,这些常量才有效。 - XML_ERROR_NONE 
    (integer)
 
     
     - XML_ERROR_NO_MEMORY 
    (integer)
 
     
     - XML_ERROR_SYNTAX 
    (integer)
 
     
     - XML_ERROR_NO_ELEMENTS 
    (integer)
 
     
     - XML_ERROR_INVALID_TOKEN 
    (integer)
 
     
     - XML_ERROR_UNCLOSED_TOKEN 
    (integer)
 
     
     - XML_ERROR_PARTIAL_CHAR 
    (integer)
 
     
     - XML_ERROR_TAG_MISMATCH 
    (integer)
 
     
     - XML_ERROR_DUPLICATE_ATTRIBUTE 
    (integer)
 
     
     - XML_ERROR_JUNK_AFTER_DOC_ELEMENT 
    (integer)
 
     
     - XML_ERROR_PARAM_ENTITY_REF 
    (integer)
 
     
     - XML_ERROR_UNDEFINED_ENTITY 
    (integer)
 
     
     - XML_ERROR_RECURSIVE_ENTITY_REF 
    (integer)
 
     
     - XML_ERROR_ASYNC_ENTITY 
    (integer)
 
     
     - XML_ERROR_BAD_CHAR_REF 
    (integer)
 
     
     - XML_ERROR_BINARY_ENTITY_REF 
    (integer)
 
     
     - XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF 
    (integer)
 
     
     - XML_ERROR_MISPLACED_XML_PI 
    (integer)
 
     
     - XML_ERROR_UNKNOWN_ENCODING 
    (integer)
 
     
     - XML_ERROR_INCORRECT_ENCODING 
    (integer)
 
     
     - XML_ERROR_UNCLOSED_CDATA_SECTION 
    (integer)
 
     
     - XML_ERROR_EXTERNAL_ENTITY_HANDLING 
    (integer)
 
     
     - XML_OPTION_CASE_FOLDING 
    (integer)
 
     
     - XML_OPTION_TARGET_ENCODING 
    (integer)
 
     
     - XML_OPTION_SKIP_TAGSTART 
    (integer)
 
     
     - XML_OPTION_SKIP_WHITE 
    (integer)
 
     
     
 大小写折叠(Case Folding)
	  元素处理函数可能会导致元素名称“大小写折叠”(case-folded)。“大小写折叠”被 XML 标准定义为“一个应用于一系列字符的过程,在该过程中,这些字符中的所有的非大写字符将被替换成它们对应大写等价字符”。换句话说,对于 XML,“大小写折叠”就是指将字符串转换成大写字符。
      
	  所有被传递给处理器函数的元素名称将默认的发生“大小写折叠”。该过程可以分别被 xml_parser_get_option() 和 xml_parser_set_option() 函数查询和控制。
      错误代码
	  以下常量被定义为 XML 的错误代码,将由 xml_parse() 返回:
       | 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 扩展库支持不同字符编码(character encoding)的 Unicode 字符集。字符编码有两种形式,它们分别是“源编码”(source encoding)和“目标编码”(target encoding)。PHP 对文档内部表示的编码方式是 UTF-8。
      
	  源编码将在 XML 文档被解析后完成。源编码可在建立一个 XML 解析器时指明(该编码方式在 XML 解析器的生命周期中不能被再次改变)。支持的编码方式包括 ISO-8859-1,US-ASCII 和 UTF-8。前两种为单字节编码,即每个字符被一个单一的字节表示。 UTF-8 支持 1 至 4 个字节的多 bit(最多 12)字符编码。PHP 默认使用 ISO-8859-1 作为源编码方式。
      
	  目标编码将在 PHP 向 XML 处理器函数传送数据时被完成。当 XML 解析器被建立后,目标编码将被设置成与源编码相同的编码方式,但该方式可在任何时候被更改。目标编码将影响字符数据、标记符名称以及处理指令目标(PI target)。
      
	  如果 XML 解析器遇到其源编码方式表示能力之外的字符,它将返回一个错误。
      
	  当 PHP 在被解析的 XML 文档中遇到当前目标编码无法表示的字符时,这些字符将被“降级”。简单的说,这些字符将被问号替换。
      范例
	 以下是 PHP 脚本解析 XML 文档的一些范例。
     XML 元素结构范例
	  第一个范例用缩进格式显示一个文档中起始元素的结构。
       例子 1. 显示 XML 元素结构 
<?php $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); ?>
 |  
  |   
     XML 标记符映射范例
       例子 2. 将 XML 映射为 HTML 
	   以下范例将 XML 文档中的标记符直接映射成 HTML 标记符。在“映射数组”中不存在的元素将被忽略。当然,该范例将只对一个特定的 XML 文档有效。
        
     
<?php $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(); // 使用大小写折叠来保证我们能在元素数组中找到这些元素名称 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 外部实体范例
	  该范例能够高亮显示 XML 源代码。它将说明如何外部实体指向处理器来包含和解析其它文档,如何处理 PIs,以及一种确定包含有 PIs 的代码的可信度。
      
	  能被该范例使用的的 XML 文档(xmltest.xml 和 xmltest2.xml)被列在该范例之后。
      
       例子 3. 外部实体范例 
<?php $file = "xmltest.xml";
  function trustedFile($file) {     // only trust local files owned by ourselves     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;             // If the parsed document is "trusted", we say it is safe             // to execute PHP code inside it.  If not, display the code             // instead.             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;
 <section id="about">
  <title>About this Document</title>
  <para>
   <!-- this is a comment -->
   <?php print 'Hi!  This is PHP version '.phpversion(); ?>
  </para>
 </section>
</chapter> |  
  |   
     
      以下文档将被 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>  |  
  |   
     
  |   |