phptal doesn't require ini_set anymore
[lhc/web/wiklou.git] / PHPTAL-NP-0.7.0 / libs / PHPTAL / XML_Parser.php
1 <?php
2 /* vim: set expandtab tabstop=4 shiftwidth=4: */
3 //
4 // Copyright (c) 2003 Laurent Bedubourg
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 //
20 // Authors: Laurent Bedubourg <laurent.bedubourg@free.fr>
21 //
22
23 require_once "Types/Errors.php";
24
25 /**
26 * PHPTAL internal xml parser.
27 *
28 * Note:
29 *
30 * I didn't use the XML/Parser package because of reference problems due to
31 * call_user_func and call_user_method.
32 *
33 * This problem should vanished with automatic object referencing in php4.4
34 * (ZendEngine2) remind me to remove this parser at this time.
35 *
36 *
37 * This class uses "xml_*" php functions to parse xml data.
38 *
39 * To create a new xml parser, extends this class and implements following
40 * methods.
41 *
42 * - onElementStart($tag, $attributes)
43 * - onElementClose($tag)
44 * - onElementData($data)
45 * - onSpecific($data)
46 *
47 * Here's an exemple of xml parser implementation.
48 *
49 * <?php
50 * require_once "PHPTAL/XML_Parser.php";
51 *
52 * class MyParser extends PHPTAL_XML_Parser
53 * {
54 * function onElementStart($tag, $attributes)
55 * {
56 * echo "new tag $tag with attributes :", endl;
57 * print_r($attributes);
58 * }
59 *
60 * function onElementClose($tag)
61 * {
62 * echo "tag ",$tag," is closed", endl;
63 * }
64 *
65 * function onElementData($data)
66 * {
67 * echo "some plain text : ", $data, endl;
68 * }
69 *
70 * function onSpecific($data)
71 * {
72 * echo "non xml data maybe <?xml...?> :", $data, endl;
73 * }
74 * };
75 *
76 * // MyParser usage :
77 * $p = new MyParser();
78 * $p->parse( $myString );
79 *
80 * ?>
81 *
82 * @author Laurent Bedubourg <laurent.bedubourg@free.fr>
83 */
84 class PHPTAL_XML_Parser
85 {
86 var $_file = '#string';
87 var $_tags = array();
88 var $_parser;
89 var $_error;
90 var $_xmlErrors = array(
91 XML_ERROR_NONE => "XML_ERROR_NONE",
92 XML_ERROR_NO_MEMORY => "XML_ERROR_NO_MEMORY",
93 XML_ERROR_SYNTAX => "XML_ERROR_SYNTAX",
94 XML_ERROR_NO_ELEMENTS => "XML_ERROR_NO_ELEMENTS",
95 XML_ERROR_INVALID_TOKEN => "XML_ERROR_INVALID_TOKEN",
96 XML_ERROR_UNCLOSED_TOKEN => "XML_ERROR_UNCLOSED_TOKEN",
97 XML_ERROR_PARTIAL_CHAR => "XML_ERROR_PARTIAL_CHAR",
98 XML_ERROR_TAG_MISMATCH => "XML_ERROR_TAG_MISMATCH",
99 XML_ERROR_DUPLICATE_ATTRIBUTE => "XML_ERROR_DUPLICATE_ATTRIBUTE",
100 XML_ERROR_JUNK_AFTER_DOC_ELEMENT => "XML_ERROR_JUNK_AFTER_DOC_ELEMENT",
101 XML_ERROR_PARAM_ENTITY_REF => "XML_ERROR_PARAM_ENTITY_REF",
102 XML_ERROR_UNDEFINED_ENTITY => "XML_ERROR_UNDEFINED_ENTITY",
103 XML_ERROR_RECURSIVE_ENTITY_REF => "XML_ERROR_RECURSIVE_ENTITY_REF",
104 XML_ERROR_ASYNC_ENTITY => "XML_ERROR_ASYNC_ENTITY",
105 XML_ERROR_BAD_CHAR_REF => "XML_ERROR_BAD_CHAR_REF",
106 XML_ERROR_BINARY_ENTITY_REF => "XML_ERROR_BINARY_ENTITY_REF",
107 XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF => "XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF",
108 XML_ERROR_MISPLACED_XML_PI => "XML_ERROR_MISPLACED_XML_PI",
109 XML_ERROR_UNKNOWN_ENCODING => "XML_ERROR_UNKNOWN_ENCODING",
110 XML_ERROR_INCORRECT_ENCODING => "XML_ERROR_INCORRECT_ENCODING",
111 XML_ERROR_UNCLOSED_CDATA_SECTION => "XML_ERROR_UNCLOSED_CDATA_SECTION",
112 XML_ERROR_EXTERNAL_ENTITY_HANDLING => "XML_ERROR_EXTERNAL_ENTITY_HANDLING",
113 );
114
115 /**
116 * XML parser constructor.
117 */
118 function PHPTAL_XML_Parser()
119 {
120 $this->__construct();
121 }
122
123 /**
124 * XML parser php4.4 constructor.
125 */
126 function __construct()
127 {
128 $this->_parser = xml_parser_create();
129 xml_set_object($this->_parser, $this);
130 xml_set_element_handler($this->_parser, "_onElementStart", "_onElementClose");
131 xml_set_character_data_handler($this->_parser, "_onElementData");
132 xml_set_default_handler($this->_parser, "_onSpecific");
133 xml_parser_set_option($this->_parser, XML_OPTION_CASE_FOLDING, 0);
134 }
135
136 /**
137 * Parse specified data and call parser implementation of callback methods.
138 *
139 * @param data string Xml data to parse.
140 */
141 function _parse($data, $eof=true)
142 {
143 $data = str_replace('&','&amp;', $data);
144 if (!xml_parse($this->_parser, $data)) {
145 // PHPTAL errors first
146 if (PEAR::isError($this->_error)) {
147 return $this->_error;
148 }
149 // then look for parser errors
150 $err = xml_get_error_code($this->_parser);
151 return PEAR::raiseError($this->_xmlErrors[$err]
152 .' in '.$this->_file
153 .' around line '.$this->getLineNumber());
154 }
155 if (PEAR::isError($this->_error)) {
156 return $this->_error;
157 }
158 return true;
159 }
160
161 function parseString($data)
162 {
163 return $this->_parse($data, true);
164 }
165
166 function parseFile($path)
167 {
168 $this->_file = $path;
169 $fp = @fopen($path, "r");
170 if (!$fp) {
171 return PEAR::raiseError($php_errormsg);
172 }
173 while ($data = fread($fp, 1024)) {
174 $err = $this->_parse($data, feof($fp));
175 if (PEAR::isError($err)) {
176 fclose($fp);
177 return $err;
178 }
179 }
180 fclose($fp);
181 }
182
183 function _onElementStart($parser, $tag, $attributes)
184 {
185 if (PEAR::isError($this->_error)) return;
186 $this->_error = $this->onElementStart($tag, $attributes);
187 }
188
189 function _onElementClose($parser, $tag)
190 {
191 if (PEAR::isError($this->_error)) return;
192 $this->_error = $this->onElementClose($tag);
193 }
194
195 function _onElementData($parser, $data)
196 {
197 if (PEAR::isError($this->_error)) return;
198 $this->_error = $this->onElementData($data);
199 }
200
201 function _onSpecific($parser, $data)
202 {
203 if (PEAR::isError($this->_error)) return;
204 $this->_error = $this->onSpecific($data);
205 }
206
207 /**
208 * Return current parser line number.
209 *
210 * @return int
211 */
212 function getLineNumber()
213 {
214 return xml_get_current_line_number($this->_parser);
215 }
216
217 //
218 // ABSTRACT METHODS
219 //
220
221 /**
222 * Abstract callback called when a new xml tag is opened.
223 *
224 * @param string tag Tag name
225 * @param hashtable attributes Associative array of attributes
226 */
227 function onElementStart($tag, $attributes){}
228
229 /**
230 * Abstract callback called when a tag is closed.
231 *
232 * @param string tag Tag name
233 */
234 function onElementClose($tag){}
235
236 /**
237 * Abstract callback called when some #cdata is found.
238 *
239 * @param string data Content
240 */
241 function onElementData($data){}
242
243 /**
244 * Abstract callback called when non tags entities appear in the document.
245 *
246 * This method is called by <?xml ...?> <% %> and other specific things like
247 * <?php ?>.
248 *
249 * @param string data strange data content.
250 */
251 function onSpecific($data){}
252 }
253
254 ?>