Initial repo created
[timetracker.git] / WEB-INF / lib / pear / PEAR / XMLParser.php
1 <?php
2 /**
3  * PEAR_XMLParser
4  *
5  * PHP versions 4 and 5
6  *
7  * @category   pear
8  * @package    PEAR
9  * @author     Greg Beaver <cellog@php.net>
10  * @author     Stephan Schmidt (original XML_Unserializer code)
11  * @copyright  1997-2009 The Authors
12  * @license   http://opensource.org/licenses/bsd-license New BSD License
13  * @version    CVS: $Id: XMLParser.php 313023 2011-07-06 19:17:11Z dufuz $
14  * @link       http://pear.php.net/package/PEAR
15  * @since      File available since Release 1.4.0a1
16  */
17
18 /**
19  * Parser for any xml file
20  * @category  pear
21  * @package   PEAR
22  * @author    Greg Beaver <cellog@php.net>
23  * @author    Stephan Schmidt (original XML_Unserializer code)
24  * @copyright 1997-2009 The Authors
25  * @license   http://opensource.org/licenses/bsd-license New BSD License
26  * @version   Release: 1.9.4
27  * @link      http://pear.php.net/package/PEAR
28  * @since     Class available since Release 1.4.0a1
29  */
30 class PEAR_XMLParser
31 {
32     /**
33      * unserilialized data
34      * @var string $_serializedData
35      */
36     var $_unserializedData = null;
37
38     /**
39      * name of the root tag
40      * @var string $_root
41      */
42     var $_root = null;
43
44     /**
45      * stack for all data that is found
46      * @var array    $_dataStack
47      */
48     var $_dataStack = array();
49
50     /**
51      * stack for all values that are generated
52      * @var array    $_valStack
53      */
54     var $_valStack = array();
55
56     /**
57      * current tag depth
58      * @var int    $_depth
59      */
60     var $_depth = 0;
61
62     /**
63      * The XML encoding to use
64      * @var string $encoding
65      */
66     var $encoding = 'ISO-8859-1';
67
68     /**
69      * @return array
70      */
71     function getData()
72     {
73         return $this->_unserializedData;
74     }
75
76     /**
77      * @param string xml content
78      * @return true|PEAR_Error
79      */
80     function parse($data)
81     {
82         if (!extension_loaded('xml')) {
83             include_once 'PEAR.php';
84             return PEAR::raiseError("XML Extension not found", 1);
85         }
86         $this->_dataStack =  $this->_valStack = array();
87         $this->_depth = 0;
88
89         if (
90             strpos($data, 'encoding="UTF-8"')
91             || strpos($data, 'encoding="utf-8"')
92             || strpos($data, "encoding='UTF-8'")
93             || strpos($data, "encoding='utf-8'")
94         ) {
95             $this->encoding = 'UTF-8';
96         }
97
98         if (version_compare(phpversion(), '5.0.0', 'lt') && $this->encoding == 'UTF-8') {
99             $data = utf8_decode($data);
100             $this->encoding = 'ISO-8859-1';
101         }
102
103         $xp = xml_parser_create($this->encoding);
104         xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, 0);
105         xml_set_object($xp, $this);
106         xml_set_element_handler($xp, 'startHandler', 'endHandler');
107         xml_set_character_data_handler($xp, 'cdataHandler');
108         if (!xml_parse($xp, $data)) {
109             $msg = xml_error_string(xml_get_error_code($xp));
110             $line = xml_get_current_line_number($xp);
111             xml_parser_free($xp);
112             include_once 'PEAR.php';
113             return PEAR::raiseError("XML Error: '$msg' on line '$line'", 2);
114         }
115         xml_parser_free($xp);
116         return true;
117     }
118
119     /**
120      * Start element handler for XML parser
121      *
122      * @access private
123      * @param  object $parser  XML parser object
124      * @param  string $element XML element
125      * @param  array  $attribs attributes of XML tag
126      * @return void
127      */
128     function startHandler($parser, $element, $attribs)
129     {
130         $this->_depth++;
131         $this->_dataStack[$this->_depth] = null;
132
133         $val = array(
134             'name'         => $element,
135             'value'        => null,
136             'type'         => 'string',
137             'childrenKeys' => array(),
138             'aggregKeys'   => array()
139        );
140
141         if (count($attribs) > 0) {
142             $val['children'] = array();
143             $val['type'] = 'array';
144             $val['children']['attribs'] = $attribs;
145         }
146
147         array_push($this->_valStack, $val);
148     }
149
150     /**
151      * post-process data
152      *
153      * @param string $data
154      * @param string $element element name
155      */
156     function postProcess($data, $element)
157     {
158         return trim($data);
159     }
160
161     /**
162      * End element handler for XML parser
163      *
164      * @access private
165      * @param  object XML parser object
166      * @param  string
167      * @return void
168      */
169     function endHandler($parser, $element)
170     {
171         $value = array_pop($this->_valStack);
172         $data  = $this->postProcess($this->_dataStack[$this->_depth], $element);
173
174         // adjust type of the value
175         switch (strtolower($value['type'])) {
176             // unserialize an array
177             case 'array':
178                 if ($data !== '') {
179                     $value['children']['_content'] = $data;
180                 }
181
182                 $value['value'] = isset($value['children']) ? $value['children'] : array();
183                 break;
184
185             /*
186              * unserialize a null value
187              */
188             case 'null':
189                 $data = null;
190                 break;
191
192             /*
193              * unserialize any scalar value
194              */
195             default:
196                 settype($data, $value['type']);
197                 $value['value'] = $data;
198                 break;
199         }
200
201         $parent = array_pop($this->_valStack);
202         if ($parent === null) {
203             $this->_unserializedData = &$value['value'];
204             $this->_root = &$value['name'];
205             return true;
206         }
207
208         // parent has to be an array
209         if (!isset($parent['children']) || !is_array($parent['children'])) {
210             $parent['children'] = array();
211             if ($parent['type'] != 'array') {
212                 $parent['type'] = 'array';
213             }
214         }
215
216         if (!empty($value['name'])) {
217             // there already has been a tag with this name
218             if (in_array($value['name'], $parent['childrenKeys'])) {
219                 // no aggregate has been created for this tag
220                 if (!in_array($value['name'], $parent['aggregKeys'])) {
221                     if (isset($parent['children'][$value['name']])) {
222                         $parent['children'][$value['name']] = array($parent['children'][$value['name']]);
223                     } else {
224                         $parent['children'][$value['name']] = array();
225                     }
226                     array_push($parent['aggregKeys'], $value['name']);
227                 }
228                 array_push($parent['children'][$value['name']], $value['value']);
229             } else {
230                 $parent['children'][$value['name']] = &$value['value'];
231                 array_push($parent['childrenKeys'], $value['name']);
232             }
233         } else {
234             array_push($parent['children'],$value['value']);
235         }
236         array_push($this->_valStack, $parent);
237
238         $this->_depth--;
239     }
240
241     /**
242      * Handler for character data
243      *
244      * @access private
245      * @param  object XML parser object
246      * @param  string CDATA
247      * @return void
248      */
249     function cdataHandler($parser, $cdata)
250     {
251         $this->_dataStack[$this->_depth] .= $cdata;
252     }
253 }