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