[ Index ]

PHP Cross Reference of JPSpan 0.4 (beta)

title

Body

[close]

/JPSpan/Unserializer/ -> XML.php (source)

   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  }


Generated: Fri Nov 26 11:42:46 2004 Cross-referenced by PHPXref 0.6