PageRenderTime 25ms CodeModel.GetById 47ms RepoModel.GetById 1ms app.codeStats 1ms

/lib/pear/HTML/Template/Flexy/Tree.php

https://bitbucket.org/blackriver/openx
PHP | 333 lines | 131 code | 62 blank | 140 comment | 21 complexity | 8e81f1140e308876b4a82678659e5a93 MD5 | raw file
  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4 |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2002 The PHP Group |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.02 of the PHP license, |
  9. // | that is bundled with this package in the file LICENSE, and is |
  10. // | available at through the world-wide-web at |
  11. // | http://www.php.net/license/2_02.txt. |
  12. // | If you did not receive a copy of the PHP license and are unable to |
  13. // | obtain it through the world-wide-web, please send a note to |
  14. // | license@php.net so we can mail you a copy immediately. |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Alan Knowles <alan@akbkhome.com> |
  17. // +----------------------------------------------------------------------+
  18. //
  19. // $Id: Tree.php 6 2006-12-15 17:27:27Z $
  20. //
  21. // The Html Tree Component of Flexy
  22. // Designed to be used on it's own
  23. //
  24. //
  25. //
  26. // The concept:
  27. // - it builds a big tokens[] array :
  28. // - filters "Text with {placeholders}" into sprintf formated strings.
  29. // - matches closers to openers eg. token[4]->close = &token[5];
  30. // - it aliases the tokens into token[0] as children as a tree
  31. // - locates the base of the file. (flexy:startchildren.
  32. // returns a nice tree..
  33. class HTML_Template_Flexy_Tree {
  34. /**
  35. * Options for Tree:
  36. * 'ignore' => dont change {xxxX} into placeholders?
  37. * 'filename' => filename of file being parsed. (for error messages.)
  38. * 'ignore_html' => return <html> elements as strings.
  39. * 'ignore_php' => DELETE/DESTROY any php code in the original template.
  40. */
  41. var $options = array(
  42. 'ignore' => false, // was flexyIgnore
  43. 'filename' => false,
  44. 'ignore_html' => false,
  45. 'ignore_php' => true,
  46. );
  47. /**
  48. * Array of all tokens (eg. nodes / text / tags etc. )
  49. * All nodes have ID's
  50. *
  51. * eg.
  52. * <b>some text</b>
  53. * [0] => Token_Tag::
  54. * tagname = '<b>'
  55. * children = array( &tag[1] );
  56. close = &tag[2];
  57. * [1] => Token_Text::'some test'
  58. * [2] => Token_Tag::
  59. * tagname = '</b>';
  60. *
  61. *
  62. * under normal situations, the tree is built into node[0], the remaining nodes are referenced by alias.
  63. * if caching is used (the nodes > 0 will not exist, and everything will just be a child of node 0.
  64. *
  65. *
  66. *
  67. * @var array
  68. * @access public
  69. */
  70. var $tokens = array();
  71. var $strings = array();
  72. /**
  73. * Run a Tokenizer and Store its results and return the tree.
  74. * It should build a DOM Tree of the HTML
  75. *
  76. * @param string $data data to parse.
  77. * @param array $options see options array.
  78. *
  79. * @access public
  80. * @return base token (really a dummy token, which contains the tree)
  81. * @static
  82. */
  83. function construct($data,$options=array())
  84. {
  85. // local caching!
  86. $md5 = md5($data);
  87. if (isset($GLOBALS[__CLASS__]['cache'][$md5])) {
  88. return $GLOBALS[__CLASS__]['cache'][$md5];
  89. }
  90. $t = new HTML_Template_Flexy_Tree;
  91. $t->options = $t->options + $options;
  92. require_once 'HTML/Template/Flexy/Token.php';
  93. $t->tokens = array(new HTML_Template_Flexy_Token);
  94. $t->tokens[0]->id =0;
  95. // process
  96. if (is_a($r = $t->tokenize($data),'PEAR_Error')) {
  97. return $r;
  98. }
  99. $t->matchClosers();
  100. $t->buildChildren(0);
  101. //new Gtk_VarDump($_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][0]);
  102. $GLOBALS[__CLASS__]['cache'][$md5] = $t->returnStart();
  103. return $GLOBALS[__CLASS__]['cache'][$md5];
  104. }
  105. /**
  106. * The core tokenizing part - runs the tokenizer on the data,
  107. * and stores the results in $this->tokens[]
  108. *
  109. * @param string Data to tokenize
  110. *
  111. * @return none | PEAR::Error
  112. * @access public|private
  113. * @see see also methods.....
  114. */
  115. function tokenize($data) {
  116. require_once 'HTML/Template/Flexy/Tokenizer.php';
  117. $tokenizer = &HTML_Template_Flexy_Tokenizer::construct($data,$this->options);
  118. // initialize state - this trys to make sure that
  119. // you dont do to many elses etc.
  120. //echo "RUNNING TOKENIZER";
  121. // step one just tokenize it.
  122. $i=1;
  123. while ($t = $tokenizer->yylex()) {
  124. if ($t == HTML_TEMPLATE_FLEXY_TOKEN_ERROR) {
  125. return HTML_Template_Flexy::raiseError(
  126. array(
  127. "HTML_Template_Flexy_Tree::Syntax error in File: %s (Line %s)\n".
  128. "Tokenizer Error: %s\n".
  129. "Context:\n\n%s\n\n >>>>>> %s\n",
  130. $this->options['filename'], $tokenizer->yyline ,
  131. $tokenizer->error,
  132. htmlspecialchars(substr($tokenizer->yy_buffer,0,$tokenizer->yy_buffer_end)),
  133. htmlspecialchars(substr($tokenizer->yy_buffer,$tokenizer->yy_buffer_end,100))
  134. )
  135. ,HTML_TEMPLATE_FLEXY_ERROR_SYNTAX ,HTML_TEMPLATE_FLEXY_ERROR_DIE);
  136. }
  137. if ($t == HTML_TEMPLATE_FLEXY_TOKEN_NONE) {
  138. continue;
  139. }
  140. if ($t->token == 'Php') {
  141. continue;
  142. }
  143. $i++;
  144. $this->tokens[$i] = $tokenizer->value;
  145. $this->tokens[$i]->id = $i;
  146. //print_r($_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$i]);
  147. }
  148. //echo "BUILT TOKENS";
  149. }
  150. /**
  151. * Match the opening and closing tags eg. </B> is the closer of <B>
  152. *
  153. * aliases the ->close to the tokens[{closeid}] element
  154. *
  155. * @return none
  156. * @access public
  157. */
  158. function matchClosers()
  159. {
  160. $res = &$this->tokens;
  161. $total = count($this->tokens);
  162. // connect open and close tags.
  163. // this is done by having a stack for each of the tag types..
  164. // then removing it when it finds the closing one
  165. // eg.
  166. // <a href=""><img src=""></a>
  167. // ends up with a stack for <a>'s and a stack for <img>'s
  168. //
  169. //
  170. //
  171. for($i=1;$i<$total;$i++) {
  172. //echo "Checking TAG $i\n";
  173. if (!isset($res[$i]->tag)) {
  174. continue;
  175. }
  176. $tag = strtoupper($res[$i]->tag);
  177. if ($tag{0} != '/') { // it's not a close tag..
  178. if (!isset($stack[$tag])) {
  179. $npos = $stack[$tag]['pos'] = 0;
  180. } else {
  181. $npos = ++$stack[$tag]['pos'];
  182. }
  183. $stack[$tag][$npos] = $i;
  184. continue;
  185. }
  186. //echo "GOT END TAG: {$res[$i]->tag}\n";
  187. $tag = substr($tag,1);
  188. if (!isset($stack[$tag]['pos'])) {
  189. continue; // unmatched
  190. }
  191. $npos = $stack[$tag]['pos'];
  192. if (!isset($stack[$tag][$npos])) {
  193. // stack is empty!!!
  194. continue;
  195. }
  196. // alias closer to opener..
  197. $this->tokens[$stack[$tag][$npos]]->close = &$this->tokens[$i];
  198. $stack[$tag]['pos']--;
  199. // take it off the stack so no one else uses it!!!
  200. unset($stack[$tag][$npos]);
  201. if ($stack[$tag]['pos'] < 0) {
  202. // too many closes - just ignore it..
  203. $stack[$tag]['pos'] = 0;
  204. }
  205. continue;
  206. // new entry on stack..
  207. }
  208. // create a dummy close for the end
  209. $i = $total;
  210. $this->tokens[$i] = new HTML_Template_Flexy_Token;
  211. $this->tokens[$i]->id = $total;
  212. $this->tokens[0]->close = &$this->tokens[$i];
  213. // now is it possible to connect children...
  214. // now we need to GLOBALIZE!! -
  215. }
  216. /**
  217. * Build the child array for each element.
  218. * RECURSIVE FUNCTION!!!!
  219. *
  220. * does not move tokens, just aliases the child nodes into the token array.
  221. *
  222. * @param int id of node to add children to.
  223. *
  224. * @access public
  225. */
  226. function buildChildren($id)
  227. {
  228. $base = &$this->tokens[$id];
  229. $base->children = array();
  230. $start = $base->id +1;
  231. $end = $base->close->id;
  232. for ($i=$start; $i<$end; $i++) {
  233. //echo "{$base->id}:{$base->tag} ADDING {$i}{$_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$i]->tag}<BR>";
  234. //if ($base->id == 1176) {
  235. // echo "<PRE>";print_r($_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$i]);
  236. // }
  237. $base->children[] = &$this->tokens[$i];
  238. if (isset($this->tokens[$i]->close)) {
  239. // if the close id is greater than my id - ignore it! -
  240. if ($this->tokens[$i]->close->id > $end) {
  241. continue;
  242. }
  243. $this->buildChildren($i);
  244. $i = $this->tokens[$i]->close->id;
  245. }
  246. }
  247. }
  248. /**
  249. * Locates Flexy:startchildren etc. if it is used.
  250. * and returns the base of the tree. (eg. otherwise token[0].
  251. *
  252. * @return HTML_Template_Flexy_Token (base of tree.)
  253. * @access public
  254. */
  255. function returnStart() {
  256. foreach(array_keys($this->tokens) as $i) {
  257. switch(true) {
  258. case isset($this->tokens[$i]->ucAttributes['FLEXYSTART']):
  259. case isset($this->tokens[$i]->ucAttributes['FLEXY:START']):
  260. $this->tokens[$i]->removeAttribute('FLEXY:START');
  261. $this->tokens[$i]->removeAttribute('FLEXYSTART');
  262. return $this->tokens[$i];
  263. case isset($this->tokens[$i]->ucAttributes['FLEXYSTARTCHILDREN']):
  264. case isset($this->tokens[$i]->ucAttributes['FLEXY:STARTCHILDREN']):
  265. $this->tokens[0]->children = $this->tokens[$i]->children;
  266. return $this->tokens[0];
  267. }
  268. }
  269. return $this->tokens[0];
  270. }
  271. }