]> git.llucax.com Git - software/bife/bife.git/blob - src/BIFE/Parser.php
Removed \n at the end of the file and added a VIM option to keep it as is.
[software/bife/bife.git] / src / BIFE / Parser.php
1 <?php
2 // vim: set expandtab tabstop=4 shiftwidth=4 binary:
3 // +--------------------------------------------------------------------+
4 // |                       BIFE - Buil It FastEr                        |
5 // +--------------------------------------------------------------------+
6 // | This file is part of BIFE.                                         |
7 // |                                                                    |
8 // | BIFE is free software; you can redistribute it and/or modify it    |
9 // | under the terms of the GNU General Public License as published by  |
10 // | the Free Software Foundation; either version 2 of the License, or  |
11 // | (at your option) any later version.                                |
12 // |                                                                    |
13 // | BIFE is distributed in the hope that it will be useful, but        |
14 // | WITHOUT ANY WARRANTY; without even the implied warranty of         |
15 // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU   |
16 // | General Public License for more details.                           |
17 // |                                                                    |
18 // | You should have received a copy of the GNU General Public License  |
19 // | along with Hooks; if not, write to the Free Software Foundation,   |
20 // | Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA      |
21 // +--------------------------------------------------------------------+
22 // | Created: Wed May 17 18:16:54 ART 2003                              |
23 // | Authors: Leandro Lucarella <luca@lugmen.org.ar>                    |
24 // +--------------------------------------------------------------------+
25 //
26 // $Id$
27 //
28
29 // +X2C Class 25 :Parser
30 /**
31  * This is the XML Parser.
32  *
33  * @package BIFE
34  * @access public
35  */
36 class BIFE_Parser {
37     /**
38      * Top level widget.
39      *
40      * @var    BIFE_Widget $root
41      * @access protected
42      */
43     var $root = null;
44
45     /**
46      * XML parser resource.
47      *
48      * @var    resource $parser
49      * @access protected
50      */
51     var $parser = null;
52
53     /**
54      * BIFE widgets stack.
55      *
56      * @var    array $stack
57      * @access protected
58      */
59     var $stack = array();
60
61     /**
62      * Fallback class to use in case that a widget class is not found.
63      *
64      * @var    string $fallback
65      * @access protected
66      */
67     var $fallback = '';
68
69     /**
70      * XML cache directory. Empty if no cahching must be done (for current dir use '.').
71      *
72      * @var    string $cache
73      * @access protected
74      */
75     var $cache = '/tmp';
76
77     /**
78      * Files required by the parsed XML file.
79      *
80      * @var    array $requires
81      * @access protected
82      */
83     var $requires = array();
84
85     // ~X2C
86
87     // +X2C Operation 30
88     /**
89      * Constructor.
90      *
91      * @param  string $fallback Fallback class name (none if empty).
92      * @param  string $cache XML cache directory. Empty is no caching will be done.
93      *
94      * @return void
95      * @access public
96      */
97     function BIFE_Parser($fallback = '', $cache = '/tmp') // ~X2C
98     {
99         $this->__construct($fallback, $cache);
100     }
101     // -X2C
102
103     // +X2C Operation 31
104     /**
105      * Constructor.
106      *
107      * @param  string $fallback Fallback class name (none if empty).
108      * @param  string $cache XML cache directory. Empty is no caching will be done.
109      *
110      * @return void
111      * @access public
112      */
113     function __construct($fallback = '', $cache = '/tmp') // ~X2C
114     {
115         $this->parser   = xml_parser_create();
116         $this->fallback = $fallback;
117         $this->cache    = $cache;
118         xml_set_object($this->parser, $this);
119         xml_set_element_handler($this->parser, 'startElement', 'endElement');
120         xml_set_character_data_handler($this->parser, 'characterData');
121     }
122     // -X2C
123
124     // +X2C Operation 32
125     /**
126      * Destructor.
127      *
128      * @return void
129      * @access public
130      */
131     function __destruct() // ~X2C
132     {
133         xml_parser_free($this->parser);
134     }
135     // -X2C
136
137     // +X2C Operation 33
138     /**
139      * XML parser start of element handler.
140      *
141      * @param  resource $parser XML parser resource.
142      * @param  string $name XML tag name.
143      * @param  array $attrs XML tag attributes.
144      *
145      * @return void
146      * @access public
147      */
148     function startElement($parser, $name, $attrs) // ~X2C
149     {
150         $class = 'bife_' . strtolower(strtr($name, ':', '_'));
151         if (!class_exists($class)) {
152             $inc = 'BIFE/' .
153                 strtr(ucwords(strtr(strtolower($name), ':', ' ')), ' ', '/') .
154                 '.php';
155             if (@include_once $inc) {
156                 $this->requires[] = $inc;
157             }
158         }
159         if (class_exists($class)) {
160             $obj =& new $class($attrs);
161             // XXX - Does this check make sense?
162             if (!is_a($obj, 'bife_widget')) {
163                 trigger_error("Class '$class' is not a BIFE_Widget.", E_USER_WARNING);
164             }
165             $this->stack[] =& $obj;
166         } else {
167             if ($this->fallback) {
168                 $class = $this->fallback;
169                 $obj =& new $class($name, $attrs);
170                 if (!is_a($obj, 'bife_fallback')) {
171                     trigger_error("Class '$class' is not a BIFE_Fallback.", E_USER_WARNING);
172                 }
173                 $this->stack[] =& $obj;
174             } else {
175                 trigger_error("Class not found '$class'.", E_USER_ERROR);
176             }
177         }
178     }
179     // -X2C
180
181     // +X2C Operation 34
182     /**
183      * XML parser end of element handler.
184      *
185      * @param  resource $parser XML parser resource.
186      * @param  string $name XML tag name.
187      *
188      * @return void
189      * @access public
190      */
191     function endElement($parser, $name) // ~X2C
192     {
193         end($this->stack);
194         $current =& $this->stack[key($this->stack)];
195         array_pop($this->stack);
196         end($this->stack);
197         $parent =& $this->stack[key($this->stack)];
198         if ($parent) {
199             $parent->addContents($current);
200         } else {
201             $this->root =& $current;
202         }
203     }
204     // -X2C
205
206     // +X2C Operation 35
207     /**
208      * XML parser character data handler.
209      *
210      * @param  resource $parser XML parser resource.
211      * @param  string $data XML character data.
212      *
213      * @return void
214      * @access public
215      */
216     function characterData($parser, $data) // ~X2C
217     {
218         end($this->stack);
219         $current =& $this->stack[key($this->stack)];
220         $current->addContents($data);
221     }
222     // -X2C
223
224     // +X2C Operation 36
225     /**
226      * Parse a string with XML data.
227      *
228      * @param  string $data XML string to parse.
229      * @param  bool $final Indicates if is the last string to parse.
230      *
231      * @return void
232      * @access public
233      */
234     function parse($data, $final = true) // ~X2C
235     {
236         if (!xml_parse($this->parser, $data, $final)) {
237             trigger_error(
238                 sprintf('XML error: %s at line %d.',
239                     xml_error_string(xml_get_error_code($this->parser)),
240                     xml_get_current_line_number($this->parser)
241                 ),
242                 E_USER_WARNING
243             );
244         }
245     }
246     // -X2C
247
248     // +X2C Operation 37
249     /**
250      * Parse a XML file with a complete and valid XML document.
251      *
252      * @param  string $filename Filename to parse.
253      *
254      * @return &BIFE_Widget
255      * @access public
256      */
257     function &parseFile($filename) // ~X2C
258     {
259         if ($this->cache) {
260             $cache = $this->cache . '/' . 'bife_parser_cache' . strtr(realpath($filename), '/', '_');
261             if (@filemtime($cache) > @filemtime($filename)) {
262                 $file = file($cache);
263                 foreach(unserialize(trim(array_shift($file))) as $required) {
264                     include_once $required;
265                 }
266                 return unserialize(join('', $file));
267             }
268         }
269         if ($fp = @fopen($filename, 'r')) {
270             while ($data = fread($fp, 4096)) {
271                 $this->parse($data, feof($fp));
272             }
273         } else {
274             trigger_error("Could not open BIFE XML input file '$filename'.",
275                 E_USER_WARNING);
276         }
277         fclose($fp);
278         if ($this->cache) {
279             $fp = fopen($cache, 'w');
280             fputs($fp, serialize($this->requires) . "\n");
281             fputs($fp, serialize($this->root));
282             fclose($fp);
283         }
284         return $this->root;
285     }
286     // -X2C
287
288     // +X2C Operation 74
289     /**
290      * Parse a XML string with a complete and valid XML document.
291      *
292      * @param  string $data XML data to parse.
293      *
294      * @return &BIFE_Widget
295      * @access public
296      */
297     function &parseString($data) // ~X2C
298     {
299         $this->parse($data, true);
300         return $this->root;
301     }
302     // -X2C
303
304 } // -X2C Class :Parser
305
306 ?>