• 用 PHP 读取和编写 XML DOM


    使用 DOM 库读取 XML

    读取格式良好的 XML 文件最容易的方式是使用编译成某些 PHP 安装的文档对象模型 (DOM)库。DOM 库把整个 XML 文档读入内存,并用节点树表示它,如图 1 所示。

    <books>
      <book>
      <author>Jack Herrington</author>
      <title>PHP Hacks</title>
      <publisher>O'Reilly</publisher>
      </book>
      <book>
      <author>Jack Herrington</author>
      <title>Podcasting Hacks</title>
      <publisher>O'Reilly</publisher>
      </book>
    </books>

    树顶部的 books 节点有两个 book 子标记。在每本书中,有 authorpublisher 和 title 几个节点。authorpublisher 和 title 节点分别有包含文本的文本子节点。

    读取图书 XML 文件并用 DOM 显示内容的代码如清单 2 所示。

      <?php
      $doc = new DOMDocument();
      $doc->load( 'books.xml' );
      
      $books = $doc->getElementsByTagName( "book" );
      foreach( $books as $book )
      {
      $authors = $book->getElementsByTagName( "author" );
      $author = $authors->item(0)->nodeValue;
      
      $publishers = $book->getElementsByTagName( "publisher" );
      $publisher = $publishers->item(0)->nodeValue;
      
      $titles = $book->getElementsByTagName( "title" );
      $title = $titles->item(0)->nodeValue;
      
      echo "$title - $author - $publisher\n";
      }
      ?>

    脚本首先创建一个 new DOMdocument 对象,用 load 方法把图书 XML 装入这个对象。之后,脚本用 getElementsByName 方法得到指定名称下的所有元素的列表。

    在 book 节点的循环中,脚本用 getElementsByName 方法获得 authorpublisher 和 title 标记的 nodeValuenodeValue 是节点中的文本。脚本然后显示这些值。

    用 SAX 解析器读取 XML

    读取 XML 的另一种方法是使用 XML Simple API(SAX)解析器。PHP 的大多数安装都包含 SAX 解析器。SAX 解析器运行在回调模型上。每次打开或关闭一个标记时,或者每次解析器看到文本时,就用节点或文本的信息回调用户定义的函数。

    SAX 解析器的优点是,它是真正轻量级的。解析器不会在内存中长期保持内容,所以可以用于非常巨大的文件。缺点是编写 SAX 解析器回调是件非常麻烦的事。清单 3 显示了使用 SAX 读取图书 XML 文件并显示内容的代码。

     <?php
      $g_books = array();
      $g_elem = null;
      
      function startElement( $parser, $name, $attrs ) 
      {
      global $g_books, $g_elem;
      if ( $name == 'BOOK' ) $g_books []= array();
      $g_elem = $name;
      }
      
      function endElement( $parser, $name ) 
      {
      global $g_elem;
      $g_elem = null;
      }
      
      function textData( $parser, $text )
      {
      global $g_books, $g_elem;
      if ( $g_elem == 'AUTHOR' ||
      $g_elem == 'PUBLISHER' ||
      $g_elem == 'TITLE' )
      {
      $g_books[ count( $g_books ) - 1 ][ $g_elem ] = $text;
      }
      }
      
      $parser = xml_parser_create();
      
      xml_set_element_handler( $parser, "startElement", "endElement" );
      xml_set_character_data_handler( $parser, "textData" );
      
      $f = fopen( 'books.xml', 'r' );
      
      while( $data = fread( $f, 4096 ) )
      {
      xml_parse( $parser, $data );
      }
      
      xml_parser_free( $parser );
      
      foreach( $g_books as $book )
      {
      echo $book['TITLE']." - ".$book['AUTHOR']." - ";
      echo $book['PUBLISHER']."\n";
      }
      ?>

    脚本首先设置 g_books 数组,它在内存中容纳所有图书和图书信息,g_elem 变量保存脚本目前正在处理的标记的名称。然后脚本定义回调函数。在这个示例中,回调函数是 startElementendElement 和 textData。在打开和关闭标记的时候,分别调用 startElement和 endElement 函数。在开始和结束标记之间的文本上面,调用 textData

    在这个示例中,startElement 标记查找 book 标记,在 book 数组中开始一个新元素。然后,textData 函数查看当前元素,看它是不是 publishertitle 或 author 标记。如果是,函数就把当前文本放入当前图书。

    为了让解析继续,脚本用 xml_parser_create 函数创建解析器。然后,设置回调句柄。之后,脚本读取文件并把文件的大块内容发送到解析器。在文件读取之后,xml_parser_free 函数删除解析器。脚本的末尾输出 g_books 数组的内容。

    可以看到,这比编写 DOM 的同样功能要困难得多。如果没有 DOM 库也没有 SAX 库该怎么办?还有替代方案么?

    用正则表达式解析 XML

    可以肯定,即使提到这个方法,有些工程师也会批评我,但是确实可以用正则表达式解析 XML。清单 4 显示了使用 preg_ 函数读取图书文件的示例。

     <?php
      $xml = "";
      $f = fopen( 'books.xml', 'r' );
      while( $data = fread( $f, 4096 ) ) { $xml .= $data; }
      fclose( $f );
      
      preg_match_all( "/\<book\>(.*?)\<\/book\>/s", 
      $xml, $bookblocks );
      
      foreach( $bookblocks[1] as $block )
      {
      preg_match_all( "/\<author\>(.*?)\<\/author\>/", 
      $block, $author );
      preg_match_all( "/\<title\>(.*?)\<\/title\>/", 
      $block, $title );
      preg_match_all( "/\<publisher\>(.*?)\<\/publisher\>/", 
      $block, $publisher );
      echo( $title[1][0]." - ".$author[1][0]." - ".
      $publisher[1][0]."\n" );
      }
      ?>

    请注意这个代码有多短。开始时,它把文件读进一个大的字符串。然后用一个 regex 函数读取每个图书项目。最后用 foreach 循环,在每个图书块间循环,并提取出 author、title 和 publisher。

    那么,缺陷在哪呢?使用正则表达式代码读取 XML 的问题是,它并没先进行检查,确保 XML 的格式良好。这意味着在读取之前,无法知道 XML 是否格式良好。而且,有些格式正确的 XML 可能与正则表达式不匹配,所以日后必须修改它们。

    我从不建议使用正则表达式读取 XML,但是有时它是兼容性最好的方式,因为正则表达式函数总是可用的。不要用正则表达式读取直接来自用户的 XML,因为无法控制这类 XML 的格式或结构。应当一直用 DOM 库或 SAX 解析器读取来自用户的 XML。

    用 DOM 编写 XML

    读取 XML 只是公式的一部分。该怎样编写 XML 呢?编写 XML 最好的方式就是用 DOM。清单 5 显示了 DOM 构建图书 XML 文件的方式。


    清单 5. 用 DOM 编写图书 XML

     <?php
      $books = array();
      $books [] = array(
      'title' => 'PHP Hacks',
      'author' => 'Jack Herrington',
      'publisher' => "O'Reilly"
      );
      $books [] = array(
      'title' => 'Podcasting Hacks',
      'author' => 'Jack Herrington',
      'publisher' => "O'Reilly"
      );
      
      $doc = new DOMDocument();
      $doc->formatOutput = true;
      
      $r = $doc->createElement( "books" );
      $doc->appendChild( $r );
      
      foreach( $books as $book )
      {
      $b = $doc->createElement( "book" );
      
      $author = $doc->createElement( "author" );
      $author->appendChild(
      $doc->createTextNode( $book['author'] )
      );
      $b->appendChild( $author );
      
      $title = $doc->createElement( "title" );
      $title->appendChild(
      $doc->createTextNode( $book['title'] )
      );
      $b->appendChild( $title );
      
      $publisher = $doc->createElement( "publisher" );
      $publisher->appendChild(
      $doc->createTextNode( $book['publisher'] )
      );
      $b->appendChild( $publisher );
      
      $r->appendChild( $b );
      }
      
      echo $doc->saveXML();
      ?>

    前面还有加上header("Content-Type:text/xml");否则输出的html

    在脚本的顶部,用一些示例图书装入了 books 数组。这个数据可以来自用户也可以来自数据库。

    示例图书装入之后,脚本创建一个 new DOMDocument,并把根节点 books 添加到它。然后脚本为每本书的 author、title 和 publisher 创建节点,并为每个节点添加文本节点。每个 book 节点的最后一步是重新把它添加到根节点 books

    脚本的末尾用 saveXML 方法把 XML 输出到控制台。(也可以用 save 方法创建一个 XML 文件。)脚本的输出如清单 6 所示。

    使用 DOM 的真正价值在于它创建的 XML 总是格式正确的。但是如果不能用 DOM 创建 XML 时该怎么办?

     

    用 PHP 编写 XML

    如果 DOM 不可用,可以用 PHP 的文本模板编写 XML。清单 7 显示了 PHP 如何构建图书 XML 文件。

    <?php
      $books = array();
      $books [] = array(
      'title' => 'PHP Hacks',
      'author' => 'Jack Herrington',
      'publisher' => "O'Reilly"
      );
      $books [] = array(
      'title' => 'Podcasting Hacks',
      'author' => 'Jack Herrington',
      'publisher' => "O'Reilly"
      );
      ?>
      <books>
      <?php
      
      foreach( $books as $book )
      {
      ?>
      <book>
      <title><?php echo( $book['title'] ); ?></title>
      <author><?php echo( $book['author'] ); ?>
      </author>
      <publisher><?php echo( $book['publisher'] ); ?>
      </publisher>
      </book>
      <?php
      }
      ?>
      </books>

    脚本的顶部与 DOM 脚本类似。脚本的底部打开 books 标记,然后在每个图书中迭代,创建 book 标记和所有的内部 titleauthor 和publisher 标记。

    这种方法的问题是对实体进行编码。为了确保实体编码正确,必须在每个项目上调用 htmlentities 函数,如清单 8 所示。

     <books>
      <?php
      
      foreach( $books as $book )
      {
      $title = htmlentities( $book['title'], ENT_QUOTES );
      $author = htmlentities( $book['author'], ENT_QUOTES );
      $publisher = htmlentities( $book['publisher'], ENT_QUOTES );
      ?>
      <book>
      <title><?php echo( $title ); ?></title>
      <author><?php echo( $author ); ?> </author>
      <publisher><?php echo( $publisher ); ?>
      </publisher>
      </book>
      <?php
      }
      ?>
      </books>

    这就是用基本的 PHP 编写 XML 的烦人之处。您以为自己创建了完美的 XML,但是在试图使用数据的时候,马上就会发现某些元素的编码不正确。

     

    结束语

    XML 周围总有许多夸大之处和混淆之处。但是,并不像您想像的那么难 —— 特别是在 PHP 这样优秀的语言中。在理解并正确地实现了 XML 之后,就会发现有许多强大的工具可以使用。XPath 和 XSLT 就是这样两个值得研究的工具

    via:http://www.ibm.com/developerworks/cn/opensource/os-xmldomphp/
  • 相关阅读:
    曾经拥有,今生无悔
    WinRAR 4.20 beta2 key!注册文件 注册码
    加谁的QQ,并聊天‘
    自己读c
    字符串和字符数组做函数参数是的区别,
    数组
    *p和++对p的影响和对*p的影响
    字符串赋给指针
    memset函数,还没看2013.12.19
    strtock函数小结。
  • 原文地址:https://www.cnblogs.com/youxin/p/2697701.html
Copyright © 2020-2023  润新知