/lib/pear/HTML/Template/Flexy/Tree.php
PHP | 333 lines | 131 code | 62 blank | 140 comment | 21 complexity | 8e81f1140e308876b4a82678659e5a93 MD5 | raw file
- <?php
- /* vim: set expandtab tabstop=4 shiftwidth=4: */
- // +----------------------------------------------------------------------+
- // | PHP Version 4 |
- // +----------------------------------------------------------------------+
- // | Copyright (c) 1997-2002 The PHP Group |
- // +----------------------------------------------------------------------+
- // | This source file is subject to version 2.02 of the PHP license, |
- // | that is bundled with this package in the file LICENSE, and is |
- // | available at through the world-wide-web at |
- // | http://www.php.net/license/2_02.txt. |
- // | If you did not receive a copy of the PHP license and are unable to |
- // | obtain it through the world-wide-web, please send a note to |
- // | license@php.net so we can mail you a copy immediately. |
- // +----------------------------------------------------------------------+
- // | Authors: Alan Knowles <alan@akbkhome.com> |
- // +----------------------------------------------------------------------+
- //
- // $Id: Tree.php 6 2006-12-15 17:27:27Z $
- //
- // The Html Tree Component of Flexy
- // Designed to be used on it's own
- //
- //
- //
- // The concept:
- // - it builds a big tokens[] array :
- // - filters "Text with {placeholders}" into sprintf formated strings.
- // - matches closers to openers eg. token[4]->close = &token[5];
- // - it aliases the tokens into token[0] as children as a tree
- // - locates the base of the file. (flexy:startchildren.
- // returns a nice tree..
- class HTML_Template_Flexy_Tree {
- /**
- * Options for Tree:
- * 'ignore' => dont change {xxxX} into placeholders?
- * 'filename' => filename of file being parsed. (for error messages.)
- * 'ignore_html' => return <html> elements as strings.
- * 'ignore_php' => DELETE/DESTROY any php code in the original template.
- */
-
- var $options = array(
- 'ignore' => false, // was flexyIgnore
- 'filename' => false,
- 'ignore_html' => false,
- 'ignore_php' => true,
- );
-
-
- /**
- * Array of all tokens (eg. nodes / text / tags etc. )
- * All nodes have ID's
- *
- * eg.
- * <b>some text</b>
- * [0] => Token_Tag::
- * tagname = '<b>'
- * children = array( &tag[1] );
- close = &tag[2];
- * [1] => Token_Text::'some test'
- * [2] => Token_Tag::
- * tagname = '</b>';
- *
- *
- * under normal situations, the tree is built into node[0], the remaining nodes are referenced by alias.
- * if caching is used (the nodes > 0 will not exist, and everything will just be a child of node 0.
- *
- *
- *
- * @var array
- * @access public
- */
-
- var $tokens = array();
- var $strings = array();
-
-
-
-
-
-
- /**
- * Run a Tokenizer and Store its results and return the tree.
- * It should build a DOM Tree of the HTML
- *
- * @param string $data data to parse.
- * @param array $options see options array.
- *
- * @access public
- * @return base token (really a dummy token, which contains the tree)
- * @static
- */
-
- function construct($data,$options=array())
- {
-
- // local caching!
- $md5 = md5($data);
- if (isset($GLOBALS[__CLASS__]['cache'][$md5])) {
- return $GLOBALS[__CLASS__]['cache'][$md5];
- }
-
- $t = new HTML_Template_Flexy_Tree;
- $t->options = $t->options + $options;
- require_once 'HTML/Template/Flexy/Token.php';
- $t->tokens = array(new HTML_Template_Flexy_Token);
- $t->tokens[0]->id =0;
-
- // process
- if (is_a($r = $t->tokenize($data),'PEAR_Error')) {
- return $r;
- }
-
- $t->matchClosers();
- $t->buildChildren(0);
- //new Gtk_VarDump($_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][0]);
-
- $GLOBALS[__CLASS__]['cache'][$md5] = $t->returnStart();
- return $GLOBALS[__CLASS__]['cache'][$md5];
- }
-
- /**
- * The core tokenizing part - runs the tokenizer on the data,
- * and stores the results in $this->tokens[]
- *
- * @param string Data to tokenize
- *
- * @return none | PEAR::Error
- * @access public|private
- * @see see also methods.....
- */
-
-
- function tokenize($data) {
- require_once 'HTML/Template/Flexy/Tokenizer.php';
- $tokenizer = &HTML_Template_Flexy_Tokenizer::construct($data,$this->options);
-
- // initialize state - this trys to make sure that
- // you dont do to many elses etc.
-
- //echo "RUNNING TOKENIZER";
- // step one just tokenize it.
- $i=1;
- while ($t = $tokenizer->yylex()) {
-
- if ($t == HTML_TEMPLATE_FLEXY_TOKEN_ERROR) {
- return HTML_Template_Flexy::raiseError(
- array(
- "HTML_Template_Flexy_Tree::Syntax error in File: %s (Line %s)\n".
- "Tokenizer Error: %s\n".
- "Context:\n\n%s\n\n >>>>>> %s\n",
- $this->options['filename'], $tokenizer->yyline ,
- $tokenizer->error,
- htmlspecialchars(substr($tokenizer->yy_buffer,0,$tokenizer->yy_buffer_end)),
- htmlspecialchars(substr($tokenizer->yy_buffer,$tokenizer->yy_buffer_end,100))
- )
- ,HTML_TEMPLATE_FLEXY_ERROR_SYNTAX ,HTML_TEMPLATE_FLEXY_ERROR_DIE);
- }
-
- if ($t == HTML_TEMPLATE_FLEXY_TOKEN_NONE) {
- continue;
- }
- if ($t->token == 'Php') {
- continue;
- }
- $i++;
- $this->tokens[$i] = $tokenizer->value;
- $this->tokens[$i]->id = $i;
-
-
-
- //print_r($_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$i]);
-
- }
- //echo "BUILT TOKENS";
- }
-
-
-
-
- /**
- * Match the opening and closing tags eg. </B> is the closer of <B>
- *
- * aliases the ->close to the tokens[{closeid}] element
- *
- * @return none
- * @access public
- */
-
- function matchClosers()
- {
- $res = &$this->tokens;
- $total = count($this->tokens);
- // connect open and close tags.
-
- // this is done by having a stack for each of the tag types..
- // then removing it when it finds the closing one
- // eg.
- // <a href=""><img src=""></a>
- // ends up with a stack for <a>'s and a stack for <img>'s
- //
- //
- //
-
-
- for($i=1;$i<$total;$i++) {
- //echo "Checking TAG $i\n";
- if (!isset($res[$i]->tag)) {
- continue;
- }
- $tag = strtoupper($res[$i]->tag);
- if ($tag{0} != '/') { // it's not a close tag..
-
-
- if (!isset($stack[$tag])) {
- $npos = $stack[$tag]['pos'] = 0;
- } else {
- $npos = ++$stack[$tag]['pos'];
- }
- $stack[$tag][$npos] = $i;
- continue;
- }
-
- //echo "GOT END TAG: {$res[$i]->tag}\n";
- $tag = substr($tag,1);
- if (!isset($stack[$tag]['pos'])) {
- continue; // unmatched
- }
-
- $npos = $stack[$tag]['pos'];
- if (!isset($stack[$tag][$npos])) {
- // stack is empty!!!
- continue;
- }
- // alias closer to opener..
- $this->tokens[$stack[$tag][$npos]]->close = &$this->tokens[$i];
- $stack[$tag]['pos']--;
- // take it off the stack so no one else uses it!!!
- unset($stack[$tag][$npos]);
- if ($stack[$tag]['pos'] < 0) {
- // too many closes - just ignore it..
- $stack[$tag]['pos'] = 0;
- }
- continue;
- // new entry on stack..
-
-
-
- }
-
- // create a dummy close for the end
- $i = $total;
- $this->tokens[$i] = new HTML_Template_Flexy_Token;
- $this->tokens[$i]->id = $total;
- $this->tokens[0]->close = &$this->tokens[$i];
-
- // now is it possible to connect children...
- // now we need to GLOBALIZE!! -
-
- }
-
- /**
- * Build the child array for each element.
- * RECURSIVE FUNCTION!!!!
- *
- * does not move tokens, just aliases the child nodes into the token array.
- *
- * @param int id of node to add children to.
- *
- * @access public
- */
- function buildChildren($id)
- {
-
-
- $base = &$this->tokens[$id];
- $base->children = array();
- $start = $base->id +1;
- $end = $base->close->id;
-
- for ($i=$start; $i<$end; $i++) {
- //echo "{$base->id}:{$base->tag} ADDING {$i}{$_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$i]->tag}<BR>";
- //if ($base->id == 1176) {
- // echo "<PRE>";print_r($_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$i]);
- // }
- $base->children[] = &$this->tokens[$i];
- if (isset($this->tokens[$i]->close)) {
-
- // if the close id is greater than my id - ignore it! -
- if ($this->tokens[$i]->close->id > $end) {
- continue;
- }
- $this->buildChildren($i);
- $i = $this->tokens[$i]->close->id;
- }
- }
- }
-
-
- /**
- * Locates Flexy:startchildren etc. if it is used.
- * and returns the base of the tree. (eg. otherwise token[0].
- *
- * @return HTML_Template_Flexy_Token (base of tree.)
- * @access public
- */
-
- function returnStart() {
-
- foreach(array_keys($this->tokens) as $i) {
- switch(true) {
- case isset($this->tokens[$i]->ucAttributes['FLEXYSTART']):
- case isset($this->tokens[$i]->ucAttributes['FLEXY:START']):
- $this->tokens[$i]->removeAttribute('FLEXY:START');
- $this->tokens[$i]->removeAttribute('FLEXYSTART');
- return $this->tokens[$i];
- case isset($this->tokens[$i]->ucAttributes['FLEXYSTARTCHILDREN']):
- case isset($this->tokens[$i]->ucAttributes['FLEXY:STARTCHILDREN']):
- $this->tokens[0]->children = $this->tokens[$i]->children;
- return $this->tokens[0];
- }
- }
- return $this->tokens[0];
-
-
- }
-
- }