Main Page | Namespace List | Class Hierarchy | Class List | File List | Class Members | File Members | Related Pages

Parser.php

Go to the documentation of this file.
00001 <?php 00002 /* vim: set expandtab tabstop=4 shiftwidth=4: */ 00003 // 00004 // Copyright (c) 2003 Laurent Bedubourg 00005 // 00006 // This library is free software; you can redistribute it and/or 00007 // modify it under the terms of the GNU Lesser General Public 00008 // License as published by the Free Software Foundation; either 00009 // version 2.1 of the License, or (at your option) any later version. 00010 // 00011 // This library is distributed in the hope that it will be useful, 00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 // Lesser General Public License for more details. 00015 // 00016 // You should have received a copy of the GNU Lesser General Public 00017 // License along with this library; if not, write to the Free Software 00018 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00019 // 00020 // Authors: Laurent Bedubourg <laurent.bedubourg@free.fr> 00021 // 00022 00023 $__d = dirname(__FILE__); 00024 require_once _phptal_os_path_join($__d, 'XML_Parser.php'); 00025 require_once _phptal_os_path_join($__d, 'Attribute.php'); 00026 require_once _phptal_os_path_join($__d, 'Expression.php'); 00027 require_once _phptal_os_path_join($__d, 'ExpressionFunctions.php'); 00028 require_once _phptal_os_path_join($__d, 'Generator.php'); 00029 require_once _phptal_os_path_join($__d, 'Tag.php'); 00030 00031 $_t = _phptal_os_path_join($__d, 'Attribute', 'TAL'); 00032 require_once _phptal_os_path_join($_t, 'Attributes.php'); 00033 require_once _phptal_os_path_join($_t, 'Comment.php'); 00034 require_once _phptal_os_path_join($_t, 'Content.php'); 00035 require_once _phptal_os_path_join($_t, 'Condition.php'); 00036 require_once _phptal_os_path_join($_t, 'Define.php'); 00037 require_once _phptal_os_path_join($_t, 'Omit_tag.php'); 00038 require_once _phptal_os_path_join($_t, 'Replace.php'); 00039 require_once _phptal_os_path_join($_t, 'On_error.php'); 00040 require_once _phptal_os_path_join($_t, 'Repeat.php'); 00041 00042 $_t = _phptal_os_path_join($__d, 'Attribute', 'PHPTAL'); 00043 require_once _phptal_os_path_join($_t, 'Include.php'); 00044 require_once _phptal_os_path_join($_t, 'Src_include.php'); 00045 00046 $_t = _phptal_os_path_join($__d, 'Attribute', 'METAL'); 00047 require_once _phptal_os_path_join($_t, 'Define_macro.php'); 00048 require_once _phptal_os_path_join($_t, 'Use_macro.php'); 00049 require_once _phptal_os_path_join($_t, 'Define_slot.php'); 00050 require_once _phptal_os_path_join($_t, 'Fill_slot.php'); 00051 00052 $_t = _phptal_os_path_join($__d, 'Attribute', 'I18N'); 00053 require_once _phptal_os_path_join($_t, 'Translate.php'); 00054 require_once _phptal_os_path_join($_t, 'Name.php'); 00055 require_once _phptal_os_path_join($_t, 'Attributes.php'); 00056 00057 00086 class PHPTAL_Parser extends PHPTAL_XML_Parser 00087 { 00088 // root gat 00089 var $_root; 00090 // document headers (string) 00091 var $_headers = false; 00092 var $_started = false; 00093 00094 var $_docType; 00095 var $_inDocType; 00096 00097 // current tag 00098 var $_current; 00099 00100 // source file name 00101 var $_file; 00102 00103 // activate xhtml empty tags lookup 00104 var $_outputFormat = PHPTAL_XHTML; 00105 00106 // keep xmlns:* attributes ? 00107 var $_keepXMLNS = false; 00108 00119 function parse($file, $src) 00120 { 00121 $this->_file = $file; 00122 $this->_initRoot(); 00123 return $this->parseString($src, true); 00124 } 00125 00138 function generateCode($func_name) 00139 { 00140 $gen = new PHPTAL_Generator($this->_file, $func_name); 00141 $gen->setHeaders($this->_headers); 00142 $err = $this->_root->generateCode($gen); 00143 if (PEAR::isError($err)) { 00144 return $err; 00145 } 00146 return $gen->getCode(); 00147 } 00148 00157 function toString() 00158 { 00159 $buf = new StringBuffer(); 00160 $buf->appendln('Template tree [\'', $this->_file, '\']'); 00161 $buf->append($this->_root->toString()); 00162 return $buf->toString(); 00163 } 00164 00165 00166 // ---------------------------------------------------------------------- 00167 // Private methods 00168 // ---------------------------------------------------------------------- 00169 00175 function _initRoot() 00176 { 00177 $this->_headers = ""; 00178 $this->_started = false; 00179 $this->_root = new PHPTAL_Tag($this, "#root", array()); 00180 $this->_current =& $this->_root; 00181 } 00182 00189 function _push(&$tag) 00190 { 00191 $this->_current->addChild($tag); 00192 unset($this->_current); 00193 $this->_current =& $tag; 00194 } 00195 00202 function _pushChild(&$tag) 00203 { 00204 $this->_current->addChild($tag); 00205 } 00206 00212 function _pop() 00213 { 00214 $temp =& $this->_current; 00215 unset($this->_current); 00216 if ($temp != $this->_root) { 00217 $this->_current =& $temp->getParent(); 00218 } else { 00219 $this->_current =& $this->_root; 00220 } 00221 } 00222 00223 /* 00224 * getter/setter for the output mode. 00225 * 00226 * @param int $mode optional 00227 * PHPTAL_XML or PHPTAL_XHTML 00228 */ 00229 function _outputMode($mode=false) 00230 { 00231 if ($mode !== false) { 00232 $this->_outputFormat = $mode; 00233 } 00234 return $this->_outputFormat; 00235 } 00236 00237 // ---------------------------------------------------------------------- 00238 // XML callbacks methods 00239 // ---------------------------------------------------------------------- 00240 00246 function onElementStart($name, $attributes) 00247 { 00248 global $_phptal_namespaces; 00249 00250 $this->_started = true; 00251 00252 if (strpos($name, ':') !== false) { 00253 list($domain, $extend) = split(':', strtoupper($name)); 00254 if (($extend == 'BLOCK') && (in_array($domain, $_phptal_namespaces))) { 00255 $attributes = PHPTAL_Parser::extendZptBlockAttributes($domain, $attributes); 00256 $attributes['tal:omit-tag'] = ''; 00257 } 00258 } 00259 00260 // separate phptal attributes from xhtml ones 00261 // if an attribute is not found, an error is raised. 00262 $split = PHPTAL_Parser::TemplateAttributes($attributes); 00263 if (PEAR::isError($split)) { 00264 return $split; 00265 } 00266 00267 // no error, the returned value is a tuple 00268 list($phptal, $attributes) = $split; 00269 00270 // sort phptal attributes 00271 $phptal = PHPTAL_Parser::OrderTemplateAttributes($phptal); 00272 if (PEAR::isError($phptal)) { 00273 return $phptal; 00274 } 00275 00276 // create the tag and add its template attributes 00277 $tag = new PHPTAL_Tag($this, $name, $attributes); 00278 foreach ($phptal as $t) { 00279 $tag->appendTemplateAttribute($t); 00280 unset($t); // $t is appended by reference 00281 } 00282 00283 $tag->line = $this->getLineNumber(); 00284 $this->_push($tag); 00285 } 00286 00293 function extendZptBlockAttributes($domain, $attributes) 00294 { 00295 global $_phptal_dictionary; 00296 $result = array(); 00297 foreach ($attributes as $key => $value) { 00298 $expected = strtoupper("$domain:$key"); 00299 if (array_key_exists($expected, $_phptal_dictionary)) { 00300 $result[$expected] = $value; 00301 } 00302 } 00303 return $result; 00304 } 00305 00311 function onElementData($data) 00312 { 00313 // ${xxxx} variables are evaluated during code 00314 // generation whithin the CodeGenerator under the 00315 // printString() method. 00316 $tag = new PHPTAL_Tag($this, "#cdata", array()); 00317 $tag->setContent($data); 00318 $this->_pushChild($tag); 00319 } 00320 00326 function onSpecific($data) 00327 { 00328 // fix xml parser '&' => '&amp;' automatic conversion 00329 $data = str_replace('&amp;', '&', $data); 00330 00331 if ($this->_current->name() == "#root" && !$this->_started) { 00332 $this->_headers .= $data; 00333 return; 00334 } 00335 $tag = new PHPTAL_Tag($this, "#cdata", array()); 00336 $tag->setContent($data); 00337 $this->_pushChild($tag); 00338 } 00339 00345 function onElementClose($name) 00346 { 00347 if ($this->_current == null) { 00348 return $this->_raiseNoTagExpected($name); 00349 } 00350 if ($this->_current->name() != $name) { 00351 return $this->_raiseUnexpectedTagClosure($name); 00352 } 00353 $this->_pop(); 00354 } 00355 00356 // ---------------------------------------------------------------------- 00357 // Static methods 00358 // ---------------------------------------------------------------------- 00359 00375 function TemplateAttributes($attrs) 00376 { 00377 global $_phptal_dictionary, $_phptal_aliases, $_phptal_namespaces; 00378 $phptal = array(); 00379 $att = array(); 00380 00381 foreach ($attrs as $key=>$exp) { 00382 00383 $test_key = strtoupper($key); 00384 $ns = preg_replace('/(:.*?)$/', '', $test_key); 00385 $sns = preg_replace('/^(.*?:)/', '', $test_key); 00386 // dictionary lookup 00387 if (array_key_exists($test_key, $_phptal_dictionary)) { 00388 $phptal[$test_key] = $exp; 00389 } 00390 // alias lookup 00391 elseif (array_key_exists($test_key, $_phptal_aliases)) { 00392 $phptal[ $_phptal_aliases[$test_key] ] = $exp; 00393 } 00394 // the namespace is known but the the attribute is not 00395 elseif (in_array($ns, $_phptal_namespaces)) { 00396 return $this->_raiseUnknownAttribute($test_key); 00397 } 00398 // regular xml/xhtml attribute (skip namespaces declaration) 00399 elseif ($ns !== 'XMLNS' || $this->_keepXMLNS 00400 || !in_array($sns, $_phptal_namespaces)) { 00401 $att[$key] = $exp; 00402 } 00403 } 00404 return array($phptal, $att); 00405 } 00406 00416 function OrderTemplateAttributes(&$phptal) 00417 { 00418 global $_phptal_rules_order, $_phptal_dictionary; 00419 00420 // order elements by their name using the rule table 00421 $result = array(); 00422 foreach ($phptal as $akey=>$exp) { 00423 00424 // retrieve attribute handler class 00425 $class = "PHPTAL_ATTRIBUTE_" . str_replace(":", "_", $akey); 00426 $class = str_replace("-", "_", $class); 00427 if (!class_exists($class)) { 00428 return $this->_raiseAttributeNotFound($akey, $class); 00429 } 00430 00431 $hdl = new $class($exp); 00432 $hdl->name = $akey; 00433 $hdl->_phptal_type = $_phptal_dictionary[$akey]; 00434 00435 // resolve attributes conflict 00436 $pos = $_phptal_rules_order[$akey]; 00437 if (array_key_exists($pos, $result)) { 00438 return $this->_raiseAttConflict($akey, $result[$pos]->name); 00439 } 00440 00441 // order elements by their order rule 00442 $result[$_phptal_rules_order[$akey]] = $hdl; 00443 unset($hdl); 00444 } 00445 return $result; 00446 } 00447 00448 // ---------------------------------------------------------------------- 00449 // Errors raising methods 00450 // ---------------------------------------------------------------------- 00451 00452 function _raiseAttributeNotFound($att, $class) 00453 { 00454 $str = sprintf("Attribute '%s' exists in dictionary but class '%s' ". 00455 "was not found", 00456 $att, $class); 00457 $err = new PHPTAL_ParseError($str); 00458 return PEAR::raiseError($err); 00459 } 00460 00461 function _raiseUnknownAttribute($att) 00462 { 00463 $str = sprintf("Unknown PHPTAL attribute '%s' in %s at line %d", 00464 $att, $this->_file, $this->getLineNumber()); 00465 $err = new PHPTAL_UnknownAttribute($str); 00466 return PEAR::raiseError($err); 00467 } 00468 00469 function _raiseUnexpectedTagClosure($name) 00470 { 00471 $str = sprintf("Non matching tag '%s' error in xml file '%s' at line %d" 00472 . endl . "waiting for end of tag '%s' declared at line %d.", 00473 $name, $this->_file, $this->getLineNumber(), 00474 $this->_current->name(), $this->_current->line); 00475 $err = new PHPTAL_ParseError($str); 00476 return PEAR::raiseError($err); 00477 } 00478 00479 function _raiseNoTagExpected($name) 00480 { 00481 $str = sprintf("Bad xml error in xml file '%s' at line %d". endl 00482 ."Found closing tag '%s' while no current tag is waited.", 00483 $this->_file, $this->getLineNumber(), $name); 00484 $err = new PHPTAL_ParseError($str); 00485 return PEAR::raiseError($err); 00486 } 00487 00488 function _raiseAttConflict($a2, $a1) 00489 { 00490 $str = sprintf('Template Attribute conflict in \'%s\' at line %d'. endl 00491 . ' %s must not be used in the same tag as %s', 00492 $this->_file, $this->getLineNumber(), $a1, $a2); 00493 $err = new PHPTAL_AttributeConflict($str); 00494 return PEAR::raiseError($err); 00495 } 00496 }; 00497 00502 class PHPTAL_ParseError extends PEAR_Error {} 00503 00507 class PHPTAL_UnknownAttribute extends PHPTAL_ParseError {} 00508 00512 class PHPTAL_AttributeConflict extends PHPTAL_ParseError {} 00513 00514 00515 ?>

Generated on Tue Jun 29 23:40:06 2004 for Mediawiki by doxygen 1.3.7