Merging trunk back onto the template parsing branch
[isso.git] / xml.php
1 <?php
2 /*=====================================================================*\
3 || ################################################################### ||
4 || # Iris Studios Shared Object Framework [#]version[#]
5 || # --------------------------------------------------------------- # ||
6 || # Copyright ©2002-[#]year[#] by Iris Studios, Inc. All Rights Reserved. # ||
7 || # This file may not be reproduced in any way without permission. # ||
8 || # --------------------------------------------------------------- # ||
9 || # User License Agreement at http://www.iris-studios.com/license/ # ||
10 || ################################################################### ||
11 \*=====================================================================*/
12
13 /**
14 * XML Parser
15 * xml.php
16 *
17 * @package ISSO
18 */
19
20 $OBJECT = 'XML Parser';
21 $CLASS = 'XML_Parser';
22 $OBJ = 'xml';
23
24 /**
25 * XML Parser
26 *
27 * This framework is a wrapper for a robust XML parser.
28 *
29 * @author Iris Studios, Inc.
30 * @copyright Copyright ©2002 - [#]year[#], Iris Studios, Inc.
31 * @version $Revision$
32 * @package ISSO
33 *
34 */
35 class XML_Parser
36 {
37 /**
38 * Parser resource
39 * @var res
40 * @see parse()
41 */
42 var $parser = null;
43
44 /**
45 * Array of all parsed tag data
46 * @var array
47 */
48 var $taginfo = array();
49
50 /**
51 * An array of function names that are to be executed for each tag name (name => function)
52 * @var array()
53 * @see parse()
54 */
55 var $taghandler = array();
56
57 /**
58 * Whether we should trim CDATA elements
59 * @var bool
60 * @see parse()
61 */
62 var $trimdata = true;
63
64 /**
65 * Attribute data parsed from the tags
66 * @var array
67 * @see _tag_start()
68 */
69 var $attrdata = array();
70
71 /**
72 * Internal tracker for the current tag
73 * @var int;
74 */
75 var $tagid = -1;
76
77 /**
78 * Internal tracker for the name of the current tag
79 * @var str
80 */
81 var $tagname = '';
82
83 /**
84 * An internal tree to sort out the nesting of elements
85 * @var array
86 */
87 var $tree = array();
88
89 /**
90 * Internal tracker for the tag above the current one
91 * @var int
92 */
93 var $parent = -1;
94
95 /**
96 * Parse an XML file
97 *
98 * @param str XML file data
99 *
100 * @return array Array with all the XML data parsed
101 */
102 function parse($data)
103 {
104 global $_isso;
105
106 // reset all the parser data before starting
107 $this->taginfo = array();
108 $this->attrdata = array();
109 $this->tagid = -1;
110 $this->tagname = '';
111 $this->tree = array();
112 $this->parentid = -1;
113
114 // create a new parser
115 $this->parser = xml_parser_create();
116 xml_set_object($this->parser, $this);
117 xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
118 xml_set_element_handler($this->parser, '_tag_start', '_tag_end');
119 xml_set_character_data_handler($this->parser, '_cdata');
120
121 // parse the data and check for errors
122 if (!xml_parse($this->parser, $data))
123 {
124 $error['code'] = xml_get_error_code($this->parser);
125 $error['string'] = xml_error_string($error['code']);
126 $error['line'] = xml_get_current_line_number($this->parser);
127 $error['column'] = xml_get_current_column_number($this->parser);
128 trigger_error(sprintf("XML Error: %s (%d) at line %d colunn %d", $error['string'], $error['code'], $error['line'], $error['column']), E_USER_ERROR);
129 exit;
130 }
131
132 // destroy the parser
133 xml_parser_free($this->parser);
134
135 // data manipulation -- kind of resource intensive :-/
136 foreach ($this->taginfo AS $tagname => $parents)
137 {
138 foreach ($parents AS $parentid => $ids)
139 {
140 foreach ($ids AS $tagid => $data)
141 {
142 // trim data if necessary
143 if ($this->trimdata)
144 {
145 $_isso->debug("data trim: on");
146 if (($trimmed = trim($data)) != '')
147 {
148 $data = $trimmed;
149 }
150 }
151
152 // if we have a data handler, operate it now
153 if (isset($this->taghandler["$tagname"]))
154 {
155 $_isso->debug("handler: " . $this->taghandler["$tagname"]);
156 if (function_exists($this->taghandler["$tagname"]))
157 {
158 $data = $this->taghandler["$tagname"]($data, $this);
159 }
160 else
161 {
162 trigger_error('Could not find the function [' . $this->taghandler["$tagname"] . '()] for the XML tag "' . $tagname . '"', E_USER_ERROR);
163 }
164 }
165
166 $return["$tagid"] = array('tagid' => $tagid, 'tagname' => $tagname, 'parentid' => $parentid, 'attributes' => $this->attrdata["$tagid"], 'data' => $data);
167 }
168 }
169 }
170
171 // place the normal order on things
172 ksort($return);
173
174 // done... send the results back
175 return $return;
176 }
177
178 /**
179 * Process the opening location of an XML tag
180 *
181 * @param res XML parser
182 * @param str Tag name
183 * @param array Tag attributes
184 */
185 function _tag_start($parser, $name, $attributes)
186 {
187 // we're opening a new tag
188 $this->tagid++;
189 $this->tagname = $name;
190
191 // copy all tag attributes
192 array_walk($attributes, 'trim');
193 $this->attrdata[ $this->tagid ] = $attributes;
194
195 // refocus the array
196 end($this->tree);
197
198 // calculate the parent
199 $this->parent = current($this->tree);
200 $this->parent = (($this->parent === false) ? -1 : $this->parent);
201
202 // add the current element onto the array
203 array_push($this->tree, $this->tagid);
204
205 // initialize the data set
206 $this->taginfo["$name"][ $this->parent ][ $this->tagid ] = '';
207 }
208
209 /**
210 * Process XML CDATA
211 *
212 * @param res XML parser
213 * @param str CDATA from tag
214 */
215 function _cdata($parser, $data)
216 {
217 // read in the CDATA
218 if ($this->parent == $this->tagid AND !isset($this->taginfo[ $this->tagname ][ $this->parent ][ $this->tagid ]))
219 {
220 $this->taginfo[ $this->tagname ][ $this->parent ][ $this->tagid ] = '';
221 }
222 $this->taginfo[ $this->tagname ][ $this->parent ][ $this->tagid ] .= $data;
223 }
224
225 /**
226 * Process the closing of an XML tag
227 *
228 * @param res XML parser
229 * @param str Tag name
230 */
231 function _tag_end($parser, $name)
232 {
233 // pop off the end element
234 array_pop($this->tree);
235 }
236 }
237
238 /*=====================================================================*\
239 || ###################################################################
240 || # $HeadURL$
241 || # $Id$
242 || ###################################################################
243 \*=====================================================================*/
244 ?>