| [ Index ] |
PHP Cross Reference of JPSpan 0.4 (beta) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * @package JPSpan 4 * @subpackage Unserialzier 5 * @version $Id: XML.php,v 1.8 2004/11/17 20:28:00 harryf Exp $ 6 */ 7 8 //--------------------------------------------------------------------------- 9 /** 10 * Handles parsing of XML requests 11 * @package JPSpan 12 * @subpackage Unserialzier 13 * @access public 14 */ 15 class JPSpan_Unserializer_XML { 16 17 /** 18 * Dictionary of tag names to data node classes 19 * @var array 20 * @access private 21 */ 22 var $dict; 23 24 /** 25 * Node stack 26 * @var array 27 * @access private 28 */ 29 var $stack; 30 31 /** 32 * Root node 33 * @var JPSpan_Unserializer_XML_Root 34 * @access private 35 */ 36 var $root; 37 38 /** 39 * Instance of the SAX parser 40 * @var int 41 * @access private 42 */ 43 var $parser; 44 45 /** 46 * Whether there's an error in parsing 47 * @var boolean (default = FALSE) 48 * @access private 49 */ 50 var $isError = FALSE; 51 52 /** 53 * Switch for when we're inside the root node 54 * @var boolean 55 * @access private 56 */ 57 var $inData = FALSE; 58 59 /** 60 * Set's up the dictionary 61 * @access public 62 */ 63 function JPSpan_Unserializer_XML() { 64 $this->dict = array( 65 'r' => 'JPSpan_Unserializer_XML_Root', 66 'n' => 'JPSpan_Unserializer_XML_Null', 67 'b' => 'JPSpan_Unserializer_XML_Boolean', 68 'i' => 'JPSpan_Unserializer_XML_Integer', 69 'd' => 'JPSpan_Unserializer_XML_Double', 70 's' => 'JPSpan_Unserializer_XML_String', 71 'a' => 'JPSpan_Unserializer_XML_Array', 72 'o' => 'JPSpan_Unserializer_XML_Object', 73 'e' => 'JPSpan_Unserializer_XML_Element', 74 ); 75 76 } 77 78 /** 79 * Sax open tag callback 80 * @access private 81 */ 82 function open(& $parser, $tag, $attrs) { 83 if ( !array_key_exists($tag,$this->dict) ) { 84 $errorMsg = 'Illegal tag name: '.$tag; 85 $this->raiseError($errorMsg); 86 return; 87 } 88 89 if ( $tag == 'r' ) { 90 $this->inData = TRUE; 91 } 92 93 if ( $this->inData ) { 94 95 $class = $this->dict[$tag]; 96 97 $current = & new $class($this, $attrs); 98 $this->stack[] = & $current; 99 100 101 if ( $tag == 'r' ) { 102 $this->root = & $current; 103 } 104 105 } 106 } 107 108 /** 109 * Sax tag cdata callback 110 * @access private 111 */ 112 function cdata(& $parser, $data) { 113 $len = count($this->stack); 114 if ( $this->stack[$len-1]->isString ) { 115 $this->stack[$len-1]->readString($data); 116 } 117 } 118 119 /** 120 * Sax close tag callback 121 * @access private 122 */ 123 function close(& $parser, $tag) { 124 125 if ( $tag == 'r' ) { 126 $this->inData = FALSE; 127 } 128 129 if ( $this->inData ) { 130 $len = count($this->stack); 131 132 $this->stack[$len-2]->add($this->stack[$len-1]); 133 134 array_pop($this->stack); 135 } 136 137 } 138 139 /** 140 * Raise an error 141 * @param string error message 142 * @access private 143 * @return void 144 */ 145 function raiseError($msg) { 146 $this->isError = TRUE; 147 $msg.= ' [byte index: '.xml_get_current_byte_index($this->parser).']'; 148 trigger_error($msg, E_USER_ERROR); 149 } 150 151 /** 152 * Unserialize some XML. If the provided param is not a string containing 153 * an XML document, it will be returned as is 154 * @param string XML to unserialize 155 * @return mixed unserialized data structure 156 * @access public 157 */ 158 function unserialize($data) { 159 160 // Return anything that's not XML immediately 161 if ( !is_string($data) || !preg_match("/^\s*<\?xml(.+)\?>/U", $data, $match) ) { 162 return $data; 163 } 164 165 $this->parser = & xml_parser_create('UTF-8'); 166 xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, false); 167 xml_set_object($this->parser, $this); 168 xml_set_element_handler($this->parser, 'open', 'close'); 169 xml_set_character_data_handler($this->parser, 'cdata'); 170 171 if (!xml_parse($this->parser, $data, TRUE)) { 172 $errorCode = xml_get_error_code($this->parser); 173 $errorMsg = 'Badly formed XML: ('.$errorCode.') '. 174 xml_error_string($this->parser); 175 $this->raiseError($errorMsg); 176 } 177 178 @xml_parser_free($this->parser); 179 180 if ( !$this->isError ) { 181 return $this->root->value; 182 } else { 183 return FALSE; 184 } 185 } 186 } 187 188 //--------------------------------------------------------------------------- 189 /** 190 * Base class for represented data elements in XML 191 * @package JPSpan 192 * @subpackage Unserialzier 193 * @access protected 194 */ 195 class JPSpan_Unserializer_XML_Node { 196 /** 197 * @var JPSpan_Unserializer_XML 198 * @access protected 199 */ 200 var $Handler; 201 202 /** 203 * @var mixed node value 204 * @access protected 205 */ 206 var $value; 207 208 /** 209 * @var boolean switch to indentify JPSpan_Unserializer_XML_Element nodes 210 * @access protected 211 */ 212 var $isElement = FALSE; 213 214 /** 215 * @var boolean switch to identify JPSpan_Unserializer_XML_String nodes 216 * @access protected 217 */ 218 var $isString = FALSE; 219 220 /** 221 * @param JPSpan_Unserializer_XML 222 * @access protected 223 */ 224 function JPSpan_Unserializer_XML_Node(& $Handler) { 225 $this->Handler = & $Handler; 226 } 227 228 /** 229 * @param JPSpan_Unserializer_XML_Node subclass 230 * @return void 231 * @access protected 232 */ 233 function add(& $child) { 234 $errorMsg = 'Scalar nodes cannot have children'; 235 $this->Handler->raiseError($errorMsg); 236 } 237 } 238 239 //--------------------------------------------------------------------------- 240 /** 241 * The root XML tag 'r'. Zero or one child tag allowed 242 * @package JPSpan 243 * @subpackage Unserialzier 244 * @access protected 245 */ 246 class JPSpan_Unserializer_XML_Root extends JPSpan_Unserializer_XML_Node { 247 248 /** 249 * Switch to track whether root as single child node 250 * @var boolean 251 * @access private 252 */ 253 var $hasValue = FALSE; 254 255 /** 256 * @param JPSpan_Unserializer_XML 257 * @param array XML attributes 258 * @access protected 259 */ 260 function JPSpan_Unserializer_XML_Root(& $Handler, $attrs) { 261 $this->Handler = & $Handler; 262 $this->value = NULL; 263 } 264 265 /** 266 * @param JPSpan_Unserializer_XML_Node subclass 267 * @return void 268 * @access protected 269 */ 270 function add($child) { 271 272 if ( !$this->hasValue ) { 273 if ( !$child->isElement ) { 274 $this->value = $child->value; 275 $this->hasValue = TRUE; 276 } else { 277 $errorMsg = 'Element nodes can only be placed inside array or object nodes'; 278 $this->Handler->raiseError($errorMsg); 279 } 280 } else { 281 $errorMsg = 'Root node can only contain a single child node'; 282 $this->Handler->raiseError($errorMsg); 283 } 284 285 } 286 } 287 288 //--------------------------------------------------------------------------- 289 /** 290 * Null variable 'n'. No children allowed 291 * @package JPSpan 292 * @subpackage Unserialzier 293 * @access protected 294 */ 295 class JPSpan_Unserializer_XML_Null extends JPSpan_Unserializer_XML_Node { 296 297 /** 298 * @param JPSpan_Unserializer_XML 299 * @param array XML attributes 300 * @access protected 301 */ 302 function JPSpan_Unserializer_XML_Null(& $Handler, $attrs) { 303 $this->Handler = & $Handler; 304 $this->value = NULL; 305 } 306 307 } 308 309 //--------------------------------------------------------------------------- 310 /** 311 * Boolean variable 'b'. Attribute 'v' required. No children allowed 312 * @package JPSpan 313 * @subpackage Unserialzier 314 * @access protected 315 */ 316 class JPSpan_Unserializer_XML_Boolean extends JPSpan_Unserializer_XML_Node { 317 318 /** 319 * @param JPSpan_Unserializer_XML 320 * @param array XML attributes 321 * @access protected 322 */ 323 function JPSpan_Unserializer_XML_Boolean(& $Handler, $attrs) { 324 $this->Handler = & $Handler; 325 326 if ( isset($attrs['v']) ) { 327 $this->value = (bool)$attrs['v']; 328 } else { 329 $errorMsg = 'Value required for boolean'; 330 $this->Handler->raiseError($errorMsg); 331 } 332 } 333 334 } 335 336 //--------------------------------------------------------------------------- 337 /** 338 * Integer variable 'i'. Attribute 'v' required. No children allowed 339 * @package JPSpan 340 * @subpackage Unserialzier 341 * @access protected 342 */ 343 class JPSpan_Unserializer_XML_Integer extends JPSpan_Unserializer_XML_Node { 344 345 /** 346 * @param JPSpan_Unserializer_XML 347 * @param array XML attributes 348 * @access protected 349 */ 350 function JPSpan_Unserializer_XML_Integer(& $Handler, $attrs) { 351 $this->Handler = & $Handler; 352 353 if ( isset($attrs['v']) ) { 354 $this->value = (int)$attrs['v']; 355 } else { 356 $errorMsg = 'Value required for integer'; 357 $this->Handler->raiseError($errorMsg); 358 } 359 } 360 361 } 362 363 //--------------------------------------------------------------------------- 364 /** 365 * Double variable 'd' - 'v' attribute required. No children allowed 366 * @package JPSpan 367 * @subpackage Unserialzier 368 * @access protected 369 */ 370 class JPSpan_Unserializer_XML_Double extends JPSpan_Unserializer_XML_Node { 371 372 /** 373 * @param JPSpan_Unserializer_XML 374 * @param array XML attributes 375 * @access protected 376 */ 377 function JPSpan_Unserializer_XML_Double(& $Handler, $attrs) { 378 $this->Handler = & $Handler; 379 380 if ( isset($attrs['v']) ) { 381 $this->value = (double)$attrs['v']; 382 } else { 383 $errorMsg = 'Value required for double'; 384 $this->Handler->raiseError($errorMsg); 385 } 386 387 } 388 389 } 390 391 //--------------------------------------------------------------------------- 392 /** 393 * String variable 's' - value passed from JPSpan_Unserializer_XML::cdata 394 * No child tags allowed 395 * @package JPSpan 396 * @subpackage Unserialzier 397 * @access protected 398 */ 399 class JPSpan_Unserializer_XML_String extends JPSpan_Unserializer_XML_Node { 400 401 /** 402 * Declare it's a string - instructs JPSpan_Unserializer_XML::cdata to 403 * pass on string values 404 * @var boolean TRUE 405 * @access private 406 */ 407 var $isString = TRUE; 408 409 /** 410 * @param JPSpan_Unserializer_XML 411 * @param array XML attributes 412 * @access protected 413 */ 414 function JPSpan_Unserializer_XML_String(& $Handler, $attrs) { 415 $this->Handler = & $Handler; 416 $this->value = ''; 417 } 418 419 /** 420 * Read some more string 421 * @param string 422 * @return void 423 * @access protected 424 */ 425 function readString($string) { 426 $this->value .= $string; 427 } 428 429 } 430 431 //--------------------------------------------------------------------------- 432 /** 433 * Array variable 'a' - can only contain 'e' tags - zero or more 434 * @package JPSpan 435 * @subpackage Unserialzier 436 * @access protected 437 */ 438 class JPSpan_Unserializer_XML_Array extends JPSpan_Unserializer_XML_Node { 439 440 /** 441 * @param JPSpan_Unserializer_XML 442 * @param array XML attributes 443 * @access protected 444 */ 445 function JPSpan_Unserializer_XML_Array(& $Handler, $attrs) { 446 $this->Handler = & $Handler; 447 $this->value = array(); 448 } 449 450 /** 451 * @param JPSpan_Unserializer_XML_Node subclass 452 * @return void 453 * @access protected 454 */ 455 function add(& $child) { 456 457 if ( $child->isElement && !is_null($child->key) ) { 458 $this->value[$child->key] = $child->value; 459 } else { 460 $errorMsg = 'Array nodes can only contain element nodes'; 461 $this->Handler->raiseError($errorMsg); 462 } 463 } 464 465 } 466 467 //--------------------------------------------------------------------------- 468 /** 469 * Object variable 'o'. Attribute 'c' (class name) required 470 * Can only contain 'e' tags - zero or more 471 * @package JPSpan 472 * @subpackage Unserialzier 473 * @access protected 474 */ 475 class JPSpan_Unserializer_XML_Object extends JPSpan_Unserializer_XML_Node { 476 477 /** 478 * @param JPSpan_Unserializer_XML 479 * @param array XML attributes 480 * @access protected 481 */ 482 function JPSpan_Unserializer_XML_Object(& $Handler, $attrs) { 483 $this->Handler = & $Handler; 484 485 if ( isset($attrs['c']) ) { 486 487 $class = $attrs['c']; 488 489 if ( !array_key_exists(strtolower($class),$GLOBALS['_JPSPAN_UNSERIALIZER_MAP']) ) { 490 491 $errorMsg = 'Illegal object type: '.strtolower($class); 492 $this->Handler->raiseError($errorMsg); 493 return; 494 } 495 496 $this->value = & new $class; 497 498 } else { 499 $errorMsg = 'Object node requires class attribute'; 500 $this->Handler->raiseError($errorMsg); 501 } 502 503 } 504 505 /** 506 * @param JPSpan_Unserializer_XML_Node subclass 507 * @return void 508 * @access protected 509 */ 510 function add(& $child) { 511 if ( $child->isElement && $child->key ) { 512 $this->value->{$child->key} = $child->value; 513 } else { 514 $errorMsg = 'Object nodes can only contain element nodes'; 515 $this->Handler->raiseError($errorMsg); 516 } 517 } 518 519 } 520 521 //--------------------------------------------------------------------------- 522 /** 523 * Array element or object property variable 'e'. Attribute 'k' (key) required 524 * Can contain zero or one child tags 525 * @package JPSpan 526 * @subpackage Unserialzier 527 * @access protected 528 */ 529 class JPSpan_Unserializer_XML_Element extends JPSpan_Unserializer_XML_Node { 530 531 /** 532 * Value of element - defaults to NULL if no child 533 * @var mixed value 534 * @access protected 535 */ 536 var $value = NULL; 537 538 /** 539 * Element key (e.g. array index or object property name) 540 * @var mixed key (string or integer) 541 * @access protected 542 */ 543 var $key = NULL; 544 545 /** 546 * Declare it's an element 547 * @var boolean TRUE 548 * @access protected 549 */ 550 var $isElement = TRUE; 551 552 /** 553 * @param JPSpan_Unserializer_XML 554 * @param array XML attributes 555 * @access protected 556 */ 557 function JPSpan_Unserializer_XML_Element(& $Handler, $attrs) { 558 $this->Handler = & $Handler; 559 560 if ( isset($attrs['k']) ) { 561 $this->key = $attrs['k']; 562 } else { 563 $errorMsg = 'Element node requires key attribute'; 564 $this->Handler->raiseError($errorMsg); 565 } 566 } 567 568 /** 569 * @param JPSpan_Unserializer_XML_Node subclass 570 * @return void 571 * @access protected 572 */ 573 function add(& $child) { 574 if ( !$child->isElement ) { 575 $this->value = $child->value; 576 } else { 577 $errorMsg = 'Element nodes can only be placed inside array or object nodes'; 578 $this->Handler->raiseError($errorMsg); 579 } 580 } 581 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Fri Nov 26 11:42:46 2004 | Cross-referenced by PHPXref 0.6 |