• 首页
  • vue
  • TypeScript
  • JavaScript
  • scss
  • css3
  • html5
  • php
  • MySQL
  • redis
  • jQuery
  • 位置: php 中文手册 -> php 外部扩展库

    XML解析器

    此扩展需要 libxml PHP 扩展。这表示需要使用--enable-libxml,尽管这将隐式完成因为 libxml 是缺省开启的。缺省情况下,此扩展使用expat compat layer 。也可使用expat

    xml_parser_create() 与 xml_parser_create_ns() 返回的 XML 资源会引用 XML 解析器实例,以被此扩展提供的函数使用。

    安装

    此扩展默认为启用,编译时可通过下列选项禁用: --disable-xml

    这些函数默认为有效的,使用了捆绑的 expat 库。您可以通过参数 --disable-xml 来屏蔽 XML 的支持。如果您将 PHP 编译为 Apache 1.3.9 或更高版本的一个模块, PHP 将自动使用 Apache 捆绑的 expat 库。如果您不希望使用该捆绑的 expat 库,请在运行 PHP 的 configure 配置脚本时使用参数--with-expat-dir=DIR,其中 DIR 应该指向 expat 安装的根目录。

    PHP 的 Windows 版本已内建对此扩展的支持。不需要载入额外的扩展来使用这些函数。

    事件处理器

    被支持的 XML 处理器
    PHP 处理器函数事件描述
    xml_set_element_handler() 当 XML 解析器遇到开始或结束标签时,会触发元素事件。 开始标签和结束标签有不同的处理器。
    xml_set_character_data_handler() 字符数据范指 XML 文档中所有非标记的内容,包括标签之间的空格。 注意,XML 解析器不会添加或删除任何空格,由应用程序(你)来判断空格是否有意义。
    xml_set_processing_instruction_handler() PHP 程序员必须熟练掌握处理指令(PI)。<?php ?>是处理指令, 其中php被称为“处理指令对象”。 除所有以“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。实例可参见 XML 外部实体例程。

    Case Folding(大写转换)

    元素处理函数可取得元素名称转换为 case-folded(大写字母)形式。 Case-folding 被定义为“将非大写字母替换为相对应的大写字母的字符串操作”。换句话说,在 XML 中,case-folding 就是转换为大写。

    默认情况下,所有的通过处理函数的元素名都被转换为大写字母。每个 XML 解析器可分别通过xml_parser_get_option()与 xml_parser_set_option()函数来查询与控制此项功能。

    错误代码

    下列常量是 XML 相关的错误代码(xml_parse()函数的返回值):

    • If you wonder, what values those constant have, here you go:
      <?php
      XML_ERROR_NONE = 0
      XML_ERROR_NO_MEMORY = 1
      XML_ERROR_SYNTAX = 2
      XML_ERROR_NO_ELEMENTS = 3
      XML_ERROR_INVALID_TOKEN = 4
      XML_ERROR_UNCLOSED_TOKEN = 5
      XML_ERROR_PARTIAL_CHAR = 6
      XML_ERROR_TAG_MISMATCH = 7
      XML_ERROR_DUPLICATE_ATTRIBUTE = 8
      XML_ERROR_JUNK_AFTER_DOC_ELEMENT = 9
      XML_ERROR_PARAM_ENTITY_REF = 10
      XML_ERROR_UNDEFINED_ENTITY = 11
      XML_ERROR_RECURSIVE_ENTITY_REF = 12
      XML_ERROR_ASYNC_ENTITY = 13
      XML_ERROR_BAD_CHAR_REF = 14
      XML_ERROR_BINARY_ENTITY_REF = 15
      XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF = 16
      XML_ERROR_MISPLACED_XML_PI = 17
      XML_ERROR_UNKNOWN_ENCODING = 18
      XML_ERROR_INCORRECT_ENCODING = 19
      XML_ERROR_UNCLOSED_CDATA_SECTION = 20
      XML_ERROR_EXTERNAL_ENTITY_HANDLING = 21
      ?>
      

      字符编码

      PHP 的 XML 扩展通过几种不同的字符编码支持» Unicode 字符集。 有两类字符编码, 原始编码 和 目标编码. 在PHP的内部展现中,文档始终是使用UTF-8编码。

      当 XML 被 解析 后,原始编码就完成了。 在创建 XML 解析器时, 可以指定原始编码(在XML 解析器此后的生命周期里,不能修改此编码)。 被支持的原始编码有 ISO-8859-1, US-ASCII 和 UTF-8. 前两种是单字节编码, 即每一个字符表现为一个字节。 UTF-8 可将字符编码为一串不定数量(最高21)的位(bit), 排列成1到4个字节。 PHP 中使用的默认原始编码是ISO-8859-1.

      当 PHP 将数据传给 XML 处理函数时,目标编码就完成了。 在创建 XML 处理器时,目标编码被设定为与原始编码相同,但可任意修改。 目标编码会影响字符数据及标签名,与处理指令目标。

      如 XML 解析器遇到原始编码所能表示的范围之外的字符时,会返回一个错误。

      如 PHP 遇到在被解析的 XML 文档中不能用所指定的目标编码表示的字符时, 这个问题字符会被“降级”。通常来说,就是那些字符会被替换成问号(?)。

      XML 元素结构例程

      第一个例程缩进显示文档中的开始元素结构。

      <?php
      $file = "data.xml";
      $depth = array();
      function startElement($parser, $name, $attrs) 
      {
          global $depth;
          for ($i = 0; $i < $depth[$parser]; $i++) {
              echo "  ";
          }
          echo "$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);
      ?>
      
      <?php
      public static function xml2array($element, $arr = array())
      {
              if(is_string($element))
              {
                  $element = (strlen($element) > 5 && substr($element, -4) === '.xml')
                                  ? simplexml_load_file(DATAPATH.$element)
                                  : simplexml_load_string($element);
              }
               $iter = 0;
              foreach($element->children() as $b)
              {
                  $a = $b->getName();
                  if(!$b->children()){
                          $arr[$a] = trim($b[0]);
                  }
                  else{
                          $arr[$a][$iter] = array();
                          $arr[$a][$iter] = self::xml2array($b,$arr[$a][$iter]);
                  }
                      $iter++;
              }
              return $arr;
          }
      }
      ?>
      

      XML 标签映射例程

      此例程直接地将 XML 标签映射为 HTML 标签。 在“map_array”中未找到的元素将被忽略。 当然,此例程只针对特定的 XML 文档类型起作用。

      <?php
      $file = "data.xml";
      $map_array = array(
          "BOLD"     => "B",
          "EMPHASIS" => "I",
          "LITERAL"  => "TT"
      );
      function startElement($parser, $name, $attrs) 
      {
          global $map_array;
          if (isset($map_array[$name])) {
              echo "";
          }
      }
      function endElement($parser, $name) 
      {
          global $map_array;
          if (isset($map_array[$name])) {
              echo "";
          }
      }
      function characterData($parser, $data) 
      {
          echo $data;
      }
      $xml_parser = xml_parser_create();
      // use case-folding so we are sure to find the tag in $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 外部实体例程

      此例程用于加亮 XML 代码。举例说明如何使用外部实体引用来包含和解析其他文档, 及处理指令是如何被处理的,及判断处理指令所包含代码是否“可信任”的一种方法

      用于此例程的 XML 文档位于此例程的下方(xmltest.xml 和 xmltest2.xml)。

      <?php
      $file = "xmltest.xml";
      function trustedFile($file) 
      {
          // 仅信任本地文件
          if (!preg_match("@^([a-z]+)\:\/\/@i", $file) 
              && fileowner($file) == getmyuid()) {
                  return true;
          }
          return false;
      }
      function startElement($parser, $name, $attribs) 
      {
          echo "<$name";
          if (count($attribs)) {
              foreach ($attribs as $k => $v) {
                  echo " $k=\"$v\"";
              }
          }
          echo ">";
      }
      function endElement($parser, $name) 
      {
          echo "</$name>";
      }
      function characterData($parser, $data) 
      {
          echo "$data";
      }
      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:%s", 
                              htmlspecialchars($data));
                  }
                  break;
          }
      }
      function defaultHandler($parser, $data) 
      {
          if (substr($data, 0, 1) == "&" && substr($data, -1, 1) == ";") {
              printf('%s', 
                      htmlspecialchars($data));
          } else {
              printf('%s', 
                      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");
      }
      echo "";
      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)));
          }
      }
      echo "
      "; echo "parse complete\n"; xml_parser_free($xml_parser); ?>