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