Home >php教程 >php手册 >用PHP解析XSL

用PHP解析XSL

WBOY
WBOYOriginal
2016-06-21 09:04:571772browse

    用PHP解析XSL

    在php的应用当中,为做到数据和代码分离需要使用模板技术。pear、phplib及不少公司都提供了相关的模板。但他们有一个共同的缺点:就是没有统一的规范,给使用者带来很多不便。另外有关的教程和范例较少,也太初浅,不易做深层次的开发应用。
    XSL是W3C组织的规范标准,随着XML的应用而发展起来。其教程随处可见,只要你有ie5就可使用。当然由于是新技术,在支持程度上尚显不足。
    这里给大家介绍一种用用PHP解析XSL的方法。该方法仅使用PHP提供的XML函数,无须难以配置的XSLT。
    先看一下例子。
    将以下内容保存为resume.xml




  唠叨
  徐祖宁
  
  1948.10
  安徽
  czjsz_ah@stats.gov.cn
   
   
  C/C++、VFP、PHP、JavaScript
   
  2001-7-19


  刁馋
  保密
  
   
  黑龙江
  yuepengfei@mail.banner.com.cn
  166581208
  7665656
   
   
  2001-8-15


  sports98
  保密
  
   
  四川
  flyruns@hotmail.com
  15787767
  11599322
   
  http://www.hiviresearch.com/cgi/report/
  2002-1-5



    将以下内容保存为resume1.xsl



个人简历






















版主信息
别名 姓名 性别 所在地 专长




    将以下内容保存为resume2.xsl



个人简历
































版主信息
别名 姓名 性别 所在地
加入时间
专长
ICQ
OICQ
主页






    在ie5以上浏览器上查看resume.xml,并可修改resume.xml中 的resume2.xsl为resume1.xsl,可看到页面的变化。当然由于不是所有的浏览器都支持这个转换,所以需要在服务器上进行转换。

    将以下内容保存为xmltest.php
require_once "xsl_class.php";
$xml = new XML;
$p = new XSL;
$p->parser("resume2.xsl",$xml->parser("resume.xml"));
$p->display();
?>
    变换其中的resume2.xsl,我们仍将看到不同的页面,只是以转变成HTML格式了。

   相关的类:
   类xml_class解析xml文档产生一个类似于domxml的结构
   类xsl_class派生于xml_class,用于解析xsl文档并模拟xsl函数,其中template尚未实现。
*****************
   xml_class.php
*****************
class Element {
  var $Element;  // 这种节点用于文档中的任何元素。元素节点的子节点可以是其内容的元素节点、注释节点、处理信息节点以及文本节点。
  var $Text;  // 文档中出现的所有文本,都分组归入到文本节点中。文本节点不可以有同为文本节点的紧接着的前或后的兄弟节点。
  var $Attribute; // 每一个元素节点都有一套自己附加的属性节点。默认的属性值以与指定属性一样的方法来处理。这些节点都没有子节点。
  var $Namespace; // 对于每一个以xlmns:和属性节点开头的元素,都有一个名称空格节点。这些节点没有子节点。
  var $ProcessingInstruction; // 每一个处理指令都有一个单独的节点。这些节点都没有子节点。
  var $Comment; // 每一个都有一个注释节点。这些节点都没有子节点。
  var $parents = array();  
  var $childs = array();  
}

class xml {
  var $tm = array();
  var $xml_parser;
  var $data = array();
  var $element = ""; // 当前节点
  var $stack = array(); // 缓存当前标头的相关参数
  var $type;

  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) {
    if($this->element != "") {
      array_push($this->stack,$this->element);
    }
    $this->element = array(Name => $name);
    if(sizeof($attribs)) {
      $this->element[Attribute] = $attribs;
    }
  }

  //处理元素的结束标头
  function endElement($parser, $name) {
    $element = array_pop($this->stack);
    if(is_array($element)) {
      $element[Element][] = $this->element;
      $this->element = $element;
    }else {
      $this->data[Root] = $this->element;
      $this->element = "";
    }
  }

  //处理字元资料标头
  function characterData($parser, $data) {
    $data = eregi_replace("^ +","",$data);
    $data = eregi_replace("^\n+","",$data);
    if(strlen($data) > 0) {
      $this->element[Text] .= $data;
    }
  }

  //处理指令标头
  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($this->trustedFile($parser_file[$parser])) {
          eval($data);
        } else {
          $this->tm[] = sprintf("Untrusted PHP code: %s",
                  htmlspecialchars($data));
        }
        break;
      default:
//        echo $target;
//        echo "==".$data;
//        echo printf("%s %s",$target,$data);
        break;
    }
  }

  //处理内定标头
  function defaultHandler($parser, $data) {
    if(substr($data, 0, 1) == "&" && substr($data, -1, 1) == ";") {
      $this->tm[] = sprintf('%s',
              htmlspecialchars($data));
    }else {
      $this->tm[] = sprintf('%s',
              htmlspecialchars($data));
    }
  }

  //处理外部实体参引标头
  function externalEntityRefHandler($parser, $openEntityNames, $base, $systemId, $publicId) {
    if ($systemId) {
      $p = new xml;
      return $p->parser($systemId);
    }
    return false;
  }

  function parser($file) {
    global $parser_file;

    if(!($fp = @fopen($file, "r"))) {
      return false;
    }
    $this->xml_parser = xml_parser_create();
    xml_set_object($this->xml_parser, &$this);  //使 XML 剖析器用对象

    xml_parser_set_option($this->xml_parser, XML_OPTION_CASE_FOLDING, 1);
    xml_set_element_handler($this->xml_parser, "startElement", "endElement");
    xml_set_character_data_handler($this->xml_parser, "characterData");
    xml_set_processing_instruction_handler($this->xml_parser, "PIHandler");
    xml_set_default_handler($this->xml_parser, "defaultHandler");
    xml_set_external_entity_ref_handler($this->xml_parser, "externalEntityRefHandler");
    
    $this->type = xml_parser_get_option($this->xml_parser, XML_OPTION_CASE_FOLDING);
    while($data = fread($fp, 4096)) {
      if(!xml_parse($this->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)));
        return false;
      }
    }
    xml_parser_free($this->xml_parser);
    return $this->data;
  }
}
?>

********************
    xsl_class.php
********************

require_once "xml_class.php";

class xsl extends xml {
  var $datastack = array();
  var $sp;
  function parser($file,$dsn=null) {
    parent::parser($file);
    if($dsn != null) {
      $this->dsn[Element][0] = $dsn[Root];
    }
  }
  //处理元素的开始标头
  function startElement($parser, $name, $attribs) {
    if(eregi("^XSL:",$name)) {
      $ar = split(":",$name);
      return array_push($this->data,array(xsl => $ar[1],command => $attribs));
    }
    if(sizeof($attribs)) {
      $att = "";
      while(list($k, $v) = each($attribs)) {
        $att .= " $k=\"$v\"";
      }
      array_push($this->data,array(tag => "$name$att"));
    }else
      array_push($this->data,array(tag => "$name"));
  }

  //处理元素的结束标头
  function endElement($parser, $name) {
    if(!eregi("^XSL:",$name)) {
      array_push($this->data,array(tag => "/$name"));
    }else {
      $ar = split(":",$name);
      array_push($this->data,array(xsl => "/$ar[1]"));
    }
  }

  //处理字元资料标头
  function characterData($parser, $data) {
    $data = eregi_replace("^[ \n]+","",$data);
    if(strlen($data) > 0) {
      array_push($this->data,array(text => "$data"));
    }
  }

  //处理指令标头
//  function PIHandler($parser, $target, $data) {
//  }

  //处理内定标头
  function defaultHandler($parser, $data) {
  }

  //处理外部实体参引标头
//  function externalEntityRefHandler($parser, $openEntityNames, $base, $systemId, $publicId) {
//  }

  // XSL指令解析
  function xsl_parser($i) {
    for(;$idata);$i++) {
      $key = $this->data[$i];
      if(isset($key[xsl]))
        if(eregi("/xsl",$key[xsl]))
          return $i;
    }
  }

  // 从数据源读取数据
  function get_data($ps) {
    if(! eregi("/",$ps)) {
      // 若是默认的层次
      $ps = join("/",$this->datastack)."/$ps";
    }
    return "[$ps]";
  }

  // 输出结果
  function display() {
    $this->stack = array();  //初始化控制栈
    $this->datastack = array();  //初始化数据栈

    $type = true;  //用于控制text项的输出
    for($id=0;$iddata);$id++) {
      $expr = $this->data[$id];
      list($key,$value) = each($expr);
      switch($key) {
        case "tag":
          echo "";
          if(eregi("^/",$value))
            echo "\n";
          break;
        case "text":
          if($type)
            echo $value;
          break;
        case "xsl":
//          echo $value;
          list(,$command) = each($expr); // 取得操作集
          $value = eregi_replace("[/-]","_",strtolower($value));
          if(eregi("eval",$value))
            $value = eregi_replace("eval","xsl_eval",$value);
          $this->$value($command,$id);
          break;
      }
    }
  }
  // 检索数据,$dsn开始的节点,$field节点名,$n匹配次数
  function find($dsn,$field,$n=0) {
    if(! isset($dsn[Element]))
      return false;
    $root = $dsn[Element];
    for($i=0;$i      if($this->type) {
        if(eregi("^".$field."$",$root[$i][Name])) {
          if(!$n--)
            return $root[$i];
        }
      }else {
        if(ereg("^".$field."$",$root[$i][Name])) {
          if(!$n--)
            return $root[$i];
        }
      }
    }
    for($i=0;$i      if($ar = $this->find($root[$i],$field,&$n))
        return $ar;
    }
    return false;
  }

  function for_each($command,&$id) {
    // 循环,将当前id压入堆栈
    array_push($this->stack,array($id,$command[SELECT],1));
    // 检索数据指针
    $data = $this->find($this->dsn,$command[SELECT]);
    // 数据指针压入堆栈
    array_push($this->datastack,$data);
  }
  function _for_each($command,&$id) {
    // 取得入口地址
    $ar = array_pop($this->stack);
    // 抛弃当前数据指针
    array_pop($this->datastack);
    // 检查是否为嵌套
    if(count($this->datastack) > 0) {
      $dsn = array_pop($this->datastack);
      array_push($this->datastack,$dsn);
    }else
      $dsn = $this->dsn;
    $n = $ar[2];
    // 检索数据指针
    $data = $this->find($dsn,$ar[1],$n);
    if($data) {
      // 如检索到,则循环
      $ar[2]++;
      array_push($this->datastack,$data);
      array_push($this->stack,$ar);
      $id = $ar[0];
    }
  }
  function value_of($command) {
    // 取得数据指针
    if(eregi("/",$command[SELECT])) {
    }else {
      if(count($this->datastack) > 0) {
        $dsn = array_pop($this->datastack);
        array_push($this->datastack,$dsn);
      }else
        $dsn = $this->dsn;
      $data = $this->find($dsn,$command[SELECT]);
    }
    print $data[Text];
  }
  function _value_of() {
  }
  function stylesheet() {
  }
  function _stylesheet() {
  }
  function template($command) {
echo join(" ",$command)."
";
  }
  function _template() {
  }
  function apply_templates($command) {
echo join(" ",$command)."
";
  }
  function _apply_templates() {
  }
  function xsl_eval() {
  }
  function _xsl_eval() {
  }
}

/**** 附录 ****
数据元素节点
Array
(
  [Name] // 节点名
  [Text]
  [Attribute]
  [Namespace]
  [Comment]
  [ProcessingInstruction]
  [Element] => Array()
)
*************/
?>



Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn