[ Index ]

PHP Cross Reference of Joomla 1.5.26 DE

title

Body

[close]

/libraries/domit/ -> xml_domit_lite_parser.php (source)

   1  <?php
   2  /**
   3  * DOMIT! Lite is a non-validating, but lightweight and fast DOM parser for PHP
   4  * @package domit-xmlparser
   5  * @subpackage domit-xmlparser-lite
   6  * @version 1.01
   7  * @copyright (C) 2004 John Heinstein. All rights reserved
   8  * @license http://www.gnu.org/copyleft/lesser.html LGPL License
   9  * @author John Heinstein <johnkarl@nbnet.nb.ca>
  10  * @link http://www.engageinteractive.com/domit/ DOMIT! Home Page
  11  * DOMIT! is Free Software
  12  **/
  13  
  14  if (!defined('DOMIT_INCLUDE_PATH')) {
  15      define('DOMIT_INCLUDE_PATH', (dirname(__FILE__) . "/"));
  16  }
  17  
  18  /** current version of DOMIT! Lite */
  19  define ('DOMIT_LITE_VERSION', '1.01');
  20  
  21  /**
  22  *@global array Flipped version of $definedEntities array, to allow two-way conversion of entities
  23  *
  24  * Made global so that Attr nodes, which have no ownerDocument property, can access the array
  25  */
  26  $GLOBALS['DOMIT_defined_entities_flip'] = array();
  27  
  28  require_once (DOMIT_INCLUDE_PATH . 'xml_domit_shared.php');
  29  
  30  /**
  31  * The base class of all DOMIT node types
  32  *
  33  * @package domit-xmlparser
  34  * @subpackage domit-xmlparser-lite
  35  * @author John Heinstein <johnkarl@nbnet.nb.ca>
  36  */
  37  class DOMIT_Lite_Node {
  38      /** @var string The name of the node, varies according to node type */
  39      var $nodeName = null;
  40      /** @var string The value of the node, varies according to node type */
  41      var $nodeValue = null;
  42      /** @var int The type of node, e.g. CDataSection */
  43      var $nodeType = null;
  44      /** @var Object A reference to the parent of the current node */
  45      var $parentNode = null;
  46      /** @var Array An array of child node references */
  47      var $childNodes = null;
  48      /** @var Object A reference to the first node in the childNodes list */
  49      var $firstChild = null;
  50      /** @var Object A reference to the last node in the childNodes list */
  51      var $lastChild = null;
  52      /** @var Object A reference to the node prior to the current node in its parents childNodes list */
  53      var $previousSibling = null;
  54      /** @var Object A reference to the node after the current node in its parents childNodes list */
  55      var $nextSibling = null;
  56      /** @var Array An array of attribute key / value pairs */
  57      var $attributes = null;
  58      /** @var Object A reference to the Document node */
  59      var $ownerDocument = null;
  60      /** @var string The unique node id */
  61      var $uid;
  62      /** @var int The number of children of the current node */
  63      var $childCount = 0;
  64  
  65      /**
  66      * Raises error if abstract class is directly instantiated
  67      */
  68  	function DOMIT_Lite_Node() {
  69          DOMIT_DOMException::raiseException(DOMIT_ABSTRACT_CLASS_INSTANTIATION_ERR,
  70               'Cannot instantiate abstract class DOMIT_Lite_Node');
  71      } //DOMIT_Lite_Node
  72  
  73      /**
  74      * DOMIT_Lite_Node constructor, assigns a uid
  75      */
  76  	function _constructor() {
  77          global $uidFactory;
  78          $this->uid = $uidFactory->generateUID();
  79      } //_constructor
  80  
  81      /**
  82      * Appends a node to the childNodes list of the current node
  83      * @abstract
  84      * @param Object The node to be appended
  85      * @return Object The appended node
  86      */
  87      function &appendChild(&$child) {
  88          DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
  89              ('Method appendChild cannot be called by class ' . get_class($this)));
  90      } //appendChild
  91  
  92      /**
  93      * Inserts a node to the childNodes list of the current node
  94      * @abstract
  95      * @param Object The node to be inserted
  96      * @param Object The node before which the insertion is to occur
  97      * @return Object The inserted node
  98      */
  99      function &insertBefore(&$newChild, &$refChild) {
 100          DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
 101              ('Method insertBefore cannot be called by class ' . get_class($this)));
 102      } //insertBefore
 103  
 104      /**
 105      * Replaces a node with another
 106      * @abstract
 107      * @param Object The new node
 108      * @param Object The old node
 109      * @return Object The new node
 110      */
 111      function &replaceChild(&$newChild, &$oldChild) {
 112          DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
 113              ('Method replaceChild cannot be called by class ' . get_class($this)));
 114      } //replaceChild
 115  
 116      /**
 117      * Removes a node from the childNodes list of the current node
 118      * @abstract
 119      * @param Object The node to be removed
 120      * @return Object The removed node
 121      */
 122      function &removeChild(&$oldChild) {
 123          DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
 124              ('Method removeChild cannot be called by class ' . get_class($this)));
 125      } //removeChild
 126  
 127      /**
 128      * Returns the index of the specified node in a childNodes list
 129      * @param Array The childNodes array to be searched
 130      * @param Object The node targeted by the search
 131      * @return int The index of the target node, or -1 if not found
 132      */
 133  	function getChildNodeIndex(&$arr, &$child) {
 134          $index = -1;
 135          $total = count($arr);
 136  
 137          for ($i = 0; $i < $total; $i++) {
 138              if ($child->uid == $arr[$i]->uid) {
 139                  $index = $i;
 140                  break;
 141              }
 142          }
 143  
 144          return $index;
 145      } //getChildNodeIndex
 146  
 147      /**
 148      * Determines whether a node has any children
 149      * @return boolean True if any child nodes are present
 150      */
 151  	function hasChildNodes() {
 152          return ($this->childCount > 0);
 153      } //hasChildNodes
 154  
 155      /**
 156      * Copies a node and/or its children
 157      * @abstract
 158      * @param boolean True if all child nodes are also to be cloned
 159      * @return Object A copy of the node and/or its children
 160      */
 161      function &cloneNode($deep = false) {
 162          DOMIT_DOMException::raiseException(DOMIT_ABSTRACT_METHOD_INVOCATION_ERR,
 163               'Cannot invoke abstract method DOMIT_Lite_Node->cloneNode($deep). Must provide an overridden method in your subclass.');
 164      } //cloneNode
 165  
 166      /**
 167      * Adds elements with the specified tag name to a NodeList collection
 168      * @param Object The NodeList collection
 169      * @param string The tag name of matching elements
 170      */
 171  	function getNamedElements(&$nodeList, $tagName) {
 172          //Implemented in DOMIT_Lite_Element.
 173          //Needs to be here though! This is called against all nodes in the document.
 174      } //getNamedElements
 175  
 176      /**
 177      * Sets the ownerDocument property of a node to the containing DOMIT_Document
 178      * @param Object A reference to the document element of the DOMIT_Document
 179      */
 180  	function setOwnerDocument(&$rootNode) {
 181          if ($rootNode->ownerDocument == null) {
 182              unset($this->ownerDocument);
 183              $this->ownerDocument = null;
 184          }
 185          else {
 186              $this->ownerDocument =& $rootNode->ownerDocument;
 187          }
 188  
 189          $total = $this->childCount;
 190  
 191          for ($i = 0; $i < $total; $i++) {
 192              $this->childNodes[$i]->setOwnerDocument($rootNode);
 193          }
 194      } //setOwnerDocument
 195  
 196      /**
 197      * Tests whether a value is null, and if so, returns a default value
 198      * @param mixed The value to be tested
 199      * @param mixed The default value
 200      * @return mixed The specified value, or the default value if null
 201      */
 202      function &nvl(&$value,$default) {
 203            if (is_null($value)) return $default;
 204            return $value;
 205      } //nvl
 206  
 207      /**
 208      * Retrieves an element or DOMIT_NodeList of elements corresponding to an Xpath-like expression.
 209      * @abstract
 210      * @param string The query pattern
 211      * @param int If a single node is to be returned (rather than the entire NodeList) the index of that node
 212      * @return mixed A NodeList or single node that matches the pattern
 213      */
 214      function &getElementsByPath($pattern, $nodeIndex = 0) {
 215           DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
 216              ('Method getElementsByPath cannot be called by class ' . get_class($this)));
 217      } //getElementsByPath
 218  
 219      /**
 220      * Returns the concatented text of the current node and its children
 221      * @return string The concatented text of the current node and its children
 222      */
 223  	function getText() {
 224          return $this->nodeValue;
 225      } //getText
 226  
 227      /**
 228      * Formats a string for presentation as HTML
 229      * @param string The string to be formatted
 230      * @param boolean True if the string is to be sent directly to output
 231      * @return string The HTML formatted string
 232      */
 233  	function forHTML($str, $doPrint = false) {
 234          require_once (DOMIT_INCLUDE_PATH . 'xml_domit_utilities.php');
 235          return DOMIT_Utilities::forHTML($str, $doPrint);
 236      } //forHTML
 237  
 238      /**
 239      * Generates an array representation of the node and its children
 240      * @abstract
 241      * @return Array A representation of the node and its children
 242      */
 243  	function toArray() {
 244          DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
 245              ('Method toArray cannot be called by class ' . get_class($this)));
 246      } //toArray
 247  
 248      /**
 249      * A node event that can be set to fire upon document loading, used for node initialization
 250      * @abstract
 251      */
 252  	function onLoad() {
 253          //you can override this method if you subclass any of the
 254          //DOMIT_Lite_Nodes. It's a way of performing
 255          //initialization of your subclass as soon as the document
 256          //has been loaded (as opposed to as soon as the current node
 257          //has been instantiated).
 258      } //onLoad
 259  
 260      /**
 261      * Clears previousSibling, nextSibling, and parentNode references from a node that has been removed
 262      */
 263  	function clearReferences() {
 264          if ($this->previousSibling != null) {
 265              unset($this->previousSibling);
 266              $this->previousSibling = null;
 267          }
 268          if ($this->nextSibling != null) {
 269              unset($this->nextSibling);
 270              $this->nextSibling = null;
 271          }
 272          if ($this->parentNode != null) {
 273              unset($this->parentNode);
 274              $this->parentNode = null;
 275          }
 276      } //clearReferences
 277  
 278      /**
 279      * Generates a normalized (formatted for readability) representation of the node and its children
 280      * @param boolean True if HTML readable output is desired
 281      * @param boolean True if illegal xml characters in text nodes and attributes should be converted to entities
 282      * @return string The formatted string representation
 283      */
 284  	function toNormalizedString($htmlSafe = false, $subEntities = false) {
 285          //require this file for generating a normalized (readable) xml string representation
 286          require_once (DOMIT_INCLUDE_PATH . 'xml_domit_utilities.php');
 287          global $DOMIT_defined_entities_flip;
 288  
 289          $result = DOMIT_Utilities::toNormalizedString($this, $subEntities, $DOMIT_defined_entities_flip);
 290  
 291          if ($htmlSafe) $result = $this->forHTML($result);
 292  
 293          return $result;
 294      } //toNormalizedString
 295  } //DOMIT_Lite_Node
 296  
 297  
 298  /**
 299  * A parent class for nodes which possess child nodes
 300  *
 301  * @package domit-xmlparser
 302  * @subpackage domit-xmlparser-lite
 303  * @author John Heinstein <johnkarl@nbnet.nb.ca>
 304  */
 305  class DOMIT_Lite_ChildNodes_Interface extends DOMIT_Lite_Node {
 306      /**
 307      * Raises error if abstract class is directly instantiated
 308      */
 309  	function DOMIT_Lite_ChildNodes_Interface() {
 310          DOMIT_DOMException::raiseException(DOMIT_ABSTRACT_CLASS_INSTANTIATION_ERR,
 311               'Cannot instantiate abstract class DOMIT_Lite_ChildNodes_Interface');
 312      } //DOMIT_Lite_ChildNodes_Interface
 313  
 314      /**
 315      * Appends a node to the childNodes list of the current node
 316      * @param Object The node to be appended
 317      * @return Object The appended node
 318      */
 319      /**
 320      * Appends a node to the childNodes list of the current node
 321      * @param Object The node to be appended
 322      * @return Object The appended node
 323      */
 324      function &appendChild(&$child) {
 325          if (!($this->hasChildNodes())) {
 326              $this->childNodes[0] =& $child;
 327              $this->firstChild =& $child;
 328          }
 329          else {
 330              //remove $child if it already exists
 331              $index = $this->getChildNodeIndex($this->childNodes, $child);
 332  
 333              if ($index != -1) {
 334                  $this->removeChild($child);
 335              }
 336  
 337              //append child
 338              $numNodes = $this->childCount;
 339              //BB: was bug auto-created wrong childnodes[-1]: added IF
 340              if ($numNodes>0) $prevSibling =& $this->childNodes[($numNodes - 1)];
 341  
 342              $this->childNodes[$numNodes] =& $child;
 343  
 344              //set next and previous relationships
 345              //BB: added this line and the else part to finish correcting bug
 346              if (isset($prevSibling)) {
 347                  $child->previousSibling =& $prevSibling;
 348                  $prevSibling->nextSibling =& $child;
 349              } else {
 350                  unset($child->previousSibling);
 351                  $child->previousSibling = null;
 352                  $this->firstChild =& $child;
 353              }
 354          }
 355  
 356          $this->lastChild =& $child;
 357          $child->parentNode =& $this;
 358  
 359          unset($child->nextSibling);
 360          $child->nextSibling = null;
 361  
 362          $child->setOwnerDocument($this);
 363          $this->childCount++;
 364  
 365          return $child;
 366      } //appendChild
 367  
 368      /**
 369      * Inserts a node to the childNodes list of the current node
 370      * @param Object The node to be inserted
 371      * @param Object The node before which the insertion is to occur
 372      * @return Object The inserted node
 373      */
 374      function &insertBefore(&$newChild, &$refChild) {
 375          if (($refChild->nodeType == DOMIT_DOCUMENT_NODE)  ||
 376              ($refChild->parentNode == null)) {
 377  
 378              DOMIT_DOMException::raiseException(DOMIT_NOT_FOUND_ERR,
 379                   'Reference child not present in the child nodes list.');
 380          }
 381  
 382          //if reference child is also the node to be inserted
 383          //leave the document as is and don't raise an exception
 384          if ($refChild->uid == $newChild->uid) {
 385              return $newChild;
 386          }
 387  
 388          //remove $newChild if it already exists
 389          $index = $this->getChildNodeIndex($this->childNodes, $newChild);
 390          if ($index != -1) {
 391              $this->removeChild($newChild);
 392          }
 393  
 394          //find index of $refChild in childNodes
 395          $index = $this->getChildNodeIndex($this->childNodes, $refChild);
 396  
 397          if ($index != -1) {
 398              //reset sibling chain
 399              if ($refChild->previousSibling != null) {
 400                  $refChild->previousSibling->nextSibling =& $newChild;
 401                  $newChild->previousSibling =& $refChild->previousSibling;
 402              }
 403              else {
 404                  $this->firstChild =& $newChild;
 405  
 406                  if ($newChild->previousSibling != null) {
 407                      unset($newChild->previousSibling);
 408                      $newChild->previousSibling = null;
 409                  }
 410              }
 411  
 412              $newChild->parentNode =& $refChild->parentNode;
 413              $newChild->nextSibling =& $refChild;
 414              $refChild->previousSibling =& $newChild;
 415  
 416              //add node to childNodes
 417              $i = $this->childCount;
 418  
 419              while ($i >= 0) {
 420                  if ($i > $index) {
 421                      $this->childNodes[$i] =& $this->childNodes[($i - 1)];
 422                  }
 423                  else if ($i == $index) {
 424                      $this->childNodes[$i] =& $newChild;
 425                  }
 426                  $i--;
 427              }
 428  
 429              $this->childCount++;
 430          }
 431          else {
 432              $this->appendChild($newChild);
 433          }
 434  
 435          $newChild->setOwnerDocument($this);
 436  
 437          return $newChild;
 438      } //insertBefore
 439  
 440      /**
 441      * Replaces a node with another
 442      * @param Object The new node
 443      * @param Object The old node
 444      * @return Object The new node
 445      */
 446      function &replaceChild(&$newChild, &$oldChild) {
 447          if ($this->hasChildNodes()) {
 448              //remove $newChild if it already exists
 449              $index = $this->getChildNodeIndex($this->childNodes, $newChild);
 450              if ($index != -1) {
 451                  $this->removeChild($newChild);
 452              }
 453  
 454              //find index of $oldChild in childNodes
 455              $index = $this->getChildNodeIndex($this->childNodes, $oldChild);
 456  
 457              if ($index != -1) {
 458                  $newChild->ownerDocument =& $oldChild->ownerDocument;
 459                  $newChild->parentNode =& $oldChild->parentNode;
 460  
 461                  //reset sibling chain
 462                  if ($oldChild->previousSibling == null) {
 463                      unset($newChild->previousSibling);
 464                      $newChild->previousSibling = null;
 465                  }
 466                  else {
 467                      $oldChild->previousSibling->nextSibling =& $newChild;
 468                      $newChild->previousSibling =& $oldChild->previousSibling;
 469                  }
 470  
 471                  if ($oldChild->nextSibling == null) {
 472                      unset($newChild->nextSibling);
 473                      $newChild->nextSibling = null;
 474                  }
 475                  else {
 476                      $oldChild->nextSibling->previousSibling =& $newChild;
 477                      $newChild->nextSibling =& $oldChild->nextSibling;
 478                  }
 479  
 480                  $this->childNodes[$index] =& $newChild;
 481  
 482                  if ($index == 0) $this->firstChild =& $newChild;
 483                  if ($index == ($this->childCount - 1)) $this->lastChild =& $newChild;
 484  
 485                  $newChild->setOwnerDocument($this);
 486  
 487                  return $newChild;
 488              }
 489          }
 490  
 491          DOMIT_DOMException::raiseException(DOMIT_NOT_FOUND_ERR,
 492              ('Reference node for replaceChild not found.'));
 493      } //replaceChild
 494  
 495      /**
 496      * Removes a node from the childNodes list of the current node
 497      * @param Object The node to be removed
 498      * @return Object The removed node
 499      */
 500      function &removeChild(&$oldChild) {
 501          if ($this->hasChildNodes()) {
 502              //find index of $oldChild in childNodes
 503              $index = $this->getChildNodeIndex($this->childNodes, $oldChild);
 504  
 505              if ($index != -1) {
 506                  //reset sibling chain
 507                  if (($oldChild->previousSibling != null) && ($oldChild->nextSibling != null)) {
 508                      $oldChild->previousSibling->nextSibling =& $oldChild->nextSibling;
 509                      $oldChild->nextSibling->previousSibling =& $oldChild->previousSibling;
 510                  }
 511                  else if (($oldChild->previousSibling != null) && ($oldChild->nextSibling == null)) {
 512                      $this->lastChild =& $oldChild->previousSibling;
 513                      unset($oldChild->previousSibling->nextSibling);
 514                      $oldChild->previousSibling->nextSibling = null;
 515                  }
 516                  else if (($oldChild->previousSibling == null) && ($oldChild->nextSibling != null)) {
 517                      unset($oldChild->nextSibling->previousSibling);
 518                      $oldChild->nextSibling->previousSibling = null;
 519                      $this->firstChild =& $oldChild->nextSibling;
 520                  }
 521                  else if (($oldChild->previousSibling == null) && ($oldChild->nextSibling == null)) {
 522                      unset($this->firstChild);
 523                      $this->firstChild = null;
 524                      unset($this->lastChild);
 525                      $this->lastChild = null;
 526                  }
 527  
 528                  $total = $this->childCount;
 529  
 530                  //remove node from childNodes
 531                  for ($i = 0; $i < $total; $i++) {
 532                      if ($i == ($total - 1)) {
 533                          array_splice($this->childNodes, $i, 1);
 534                      }
 535                      else if ($i >= $index) {
 536                          $this->childNodes[$i] =& $this->childNodes[($i + 1)];
 537                      }
 538                  }
 539  
 540                  $this->childCount--;
 541  
 542                  $oldChild->clearReferences();
 543                  return $oldChild;
 544              }
 545          }
 546  
 547          DOMIT_DOMException::raiseException(DOMIT_NOT_FOUND_ERR,
 548                  ('Target node for removeChild not found.'));
 549      } //removeChild
 550  
 551      /**
 552      * Searches the element tree for an element with the specified attribute name and value.
 553      * @param string The value of the attribute
 554      * @param string The name of the attribute
 555      * @param boolean True if the first found node is to be returned as a node instead of a nodelist
 556      * @param boolean True if uid is to be considered an attribute
 557      * @return object A NodeList of found elements, or null
 558      */
 559      function &getElementsByAttribute($attrName = 'id', $attrValue = '',
 560                          $returnFirstFoundNode = false, $treatUIDAsAttribute = false) {
 561          require_once (DOMIT_INCLUDE_PATH . 'xml_domit_nodemaps.php');
 562  
 563          $nodelist = new DOMIT_NodeList();
 564  
 565          switch ($this->nodeType) {
 566              case DOMIT_ELEMENT_NODE:
 567                  $this->_getElementsByAttribute($nodelist, $attrName, $attrValue,
 568                                          $returnFirstFoundNode, $treatUIDAsAttribute);
 569                  break;
 570  
 571              case DOMIT_DOCUMENT_NODE:
 572                  if ($this->documentElement != null) {
 573                      $this->documentElement->_getElementsByAttribute($nodelist,
 574                          $attrName, $attrValue, $returnFirstFoundNode, $treatUIDAsAttribute);
 575                  }
 576                  break;
 577          }
 578  
 579          if ($returnFirstFoundNode) {
 580              if ($nodelist->getLength() > 0) {
 581                  return $nodelist->item(0);
 582              }
 583              $null = null;
 584              return $null;
 585          }
 586  
 587          return $nodelist;
 588      } //getElementsByAttribute
 589  
 590      /**
 591      * Searches the element tree for an element with the specified attribute name and value.
 592      * @param object The node list of found elements
 593      * @param string The value of the attribute
 594      * @param string The name of the attribute
 595      * @param boolean True if the first found node is to be returned as a node instead of a nodelist
 596      * @param boolean True if uid is to be considered an attribute
 597      * @param boolean True the node has been found
 598      */
 599  	function _getElementsByAttribute(&$nodelist, $attrName, $attrValue,
 600                          $returnFirstFoundNode, $treatUIDAsAttribute, $foundNode = false) {
 601          if (!($foundNode && $returnFirstFoundNode)) {
 602              if (($this->getAttribute($attrName) == $attrValue) ||
 603                  ($treatUIDAsAttribute && ($attrName == 'uid') && ($this->uid == $attrValue))) {
 604                  $nodelist->appendNode($this);
 605                  $foundNode = true;
 606                  if ($returnFirstFoundNode) return;
 607              }
 608  
 609              $total = $this->childCount;
 610  
 611              for ($i = 0; $i < $total; $i++) {
 612                  $currNode =& $this->childNodes[$i];
 613  
 614                  if ($currNode->nodeType == DOMIT_ELEMENT_NODE) {
 615                      $currNode->_getElementsByAttribute($nodelist,
 616                                      $attrName, $attrValue, $returnFirstFoundNode,
 617                                      $treatUIDAsAttribute, $foundNode);
 618                  }
 619              }
 620          }
 621      } //_getElementsByAttribute
 622  } //DOMIT_Lite_ChildNodes_Interface
 623  
 624  /**
 625  * A class representing the DOM Document
 626  *
 627  * @package domit-xmlparser
 628  * @subpackage domit-xmlparser-lite
 629  * @author John Heinstein <johnkarl@nbnet.nb.ca>
 630  */
 631  class DOMIT_Lite_Document extends DOMIT_Lite_ChildNodes_Interface {
 632      /** @var string The xml declaration text */
 633      var $xmlDeclaration;
 634      /** @var string The doctype text */
 635      var $doctype;
 636      /** @var Object A reference to the root node of the DOM document */
 637      var $documentElement;
 638      /** @var string The parser used to process the DOM document, either "EXPAT" or "SAXY_LITE" */
 639      var $parser;
 640      /** @var Object A reference to the DOMIT_DOMImplementation object */
 641      var $implementation;
 642      /** @var Array User defined translation table for XML entities */
 643      var $definedEntities = array();
 644      /** @var boolean If true, loadXML or parseXML will attempt to detect and repair invalid xml */
 645      var $doResolveErrors = false;
 646      /** @var boolean True if whitespace is to be preserved during parsing */
 647      var $preserveWhitespace = false;
 648      /** @var boolean If true, elements tags will be rendered to string as <element></element> rather than <element/> */
 649      var $doExpandEmptyElementTags = false;
 650      /** @var array A list of exceptions to the empty element expansion rule */
 651      var $expandEmptyElementExceptions = array();
 652      /** @var int The error code returned by the SAX parser */
 653      var $errorCode = 0;
 654      /** @var string The error string returned by the SAX parser */
 655      var $errorString = '';
 656      /** @var object A reference to a http connection or proxy server, if one is required */
 657      var $httpConnection = null;
 658      /** @var boolean True if php_http_client_generic is to be used instead of PHP get_file_contents to retrieve xml data */
 659      var $doUseHTTPClient = false;
 660  
 661      /**
 662      * DOM Document constructor
 663      */
 664  	function DOMIT_Lite_Document() {
 665          $this->_constructor();
 666          $this->xmlDeclaration = '';
 667          $this->doctype = '';
 668          $this->documentElement = null;
 669          $this->nodeType = DOMIT_DOCUMENT_NODE;
 670          $this->nodeName = '#document';
 671          $this->ownerDocument =& $this;
 672          $this->parser = '';
 673          $this->implementation = new DOMIT_DOMImplementation();
 674      } //DOMIT_Lite_Document
 675  
 676      /**
 677      * Specifies whether DOMIT! Lite will try to fix invalid XML before parsing begins
 678      * @param boolean True if errors are to be resolved
 679      */
 680  	function resolveErrors($truthVal) {
 681          $this->doResolveErrors = $truthVal;
 682      } //resolveErrors
 683  
 684      /**
 685      * Specifies the parameters of the http conection used to obtain the xml data
 686      * @param string The ip address or domain name of the connection
 687      * @param string The path of the connection
 688      * @param int The port that the connection is listening on
 689      * @param int The timeout value for the connection
 690      * @param string The user name, if authentication is required
 691      * @param string The password, if authentication is required
 692      */
 693  	function setConnection($host, $path = '/', $port = 80, $timeout = 0, $user = null, $password = null) {
 694          require_once (DOMIT_INCLUDE_PATH . 'php_http_client_generic.php');
 695  
 696          $this->httpConnection = new php_http_client_generic($host, $path, $port, $timeout, $user, $password);
 697      } //setConnection
 698  
 699      /**
 700      * Specifies whether DOMIT! preserves whitespace when parsing
 701      * @param boolean True if whitespace is to be preserved
 702      */
 703  	function preserveWhitespace($truthVal) {
 704          $this->preserveWhitespace = $truthVal;
 705      } //preserveWhitespace
 706  
 707      /**
 708      * Specifies basic authentication for an http connection
 709      * @param string The user name
 710      * @param string The password
 711      */
 712  	function setAuthorization($user, $password) {
 713          $this->httpConnection->setAuthorization($user, $password);
 714      } //setAuthorization
 715  
 716      /**
 717      * Specifies that a proxy is to be used to obtain the xml data
 718      * @param string The ip address or domain name of the proxy
 719      * @param string The path to the proxy
 720      * @param int The port that the proxy is listening on
 721      * @param int The timeout value for the connection
 722      * @param string The user name, if authentication is required
 723      * @param string The password, if authentication is required
 724      */
 725  	function setProxyConnection($host, $path = '/', $port = 80, $timeout = 0, $user = null, $password = null) {
 726          require_once (DOMIT_INCLUDE_PATH . 'php_http_proxy.php');
 727  
 728          $this->httpConnection = new php_http_proxy($host, $path, $port, $timeout, $user, $password);
 729      } //setProxyConnection
 730  
 731      /**
 732      * Specifies basic authentication for the proxy
 733      * @param string The user name
 734      * @param string The password
 735      */
 736  	function setProxyAuthorization($user, $password) {
 737          $this->httpConnection->setProxyAuthorization($user, $password);
 738      } //setProxyAuthorization
 739  
 740      /**
 741      * Specifies whether an HTTP client should be used to establish a connection
 742      * @param boolean True if an HTTP client is to be used to establish the connection
 743      */
 744  	function useHTTPClient($truthVal) {
 745          $this->doUseHTTPClient = $truthVal;
 746      } //useHTTPClient
 747  
 748      /**
 749      * Returns the error code from the underlying SAX parser
 750      * @return int The error code
 751      */
 752  	function getErrorCode() {
 753          return $this->errorCode;
 754      } //getErrorCode
 755  
 756      /**
 757      * Returns the error string from the underlying SAX parser
 758      * @return string The error string
 759      */
 760  	function getErrorString() {
 761          return $this->errorString;
 762      } //getErrorString
 763  
 764      /**
 765      * Specifies whether elements tags will be rendered to string as <element></element> rather than <element/>
 766      * @param boolean True if the expanded form is to be used
 767      * @param mixed An array of tag names that should be excepted from expandEmptyElements rule (optional)
 768      */
 769  	function expandEmptyElementTags($truthVal, $expandEmptyElementExceptions = false) {
 770          $this->doExpandEmptyElementTags = $truthVal;
 771  
 772          if (is_array($expandEmptyElementExceptions)) {
 773              $this->expandEmptyElementExceptions = $expandEmptyElementExceptions;
 774          }
 775      } //expandEmptyElementTags
 776  
 777      /**
 778      * Set the specified node as document element
 779      * @param Object The node that is to become document element
 780      * @return Object The new document element
 781      */
 782      function &setDocumentElement(&$node) {
 783          if ($node->nodeType == DOMIT_ELEMENT_NODE) {
 784              if ($this->documentElement == null) {
 785                  parent::appendChild($node);
 786              }
 787              else {
 788                  parent::replaceChild($node, $this->documentElement);
 789              }
 790  
 791              $this->documentElement =& $node;
 792          }
 793          else {
 794              DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
 795                  ('Cannot add a node of type ' . get_class($node) . ' as a Document Element.'));
 796          }
 797  
 798          return $node;
 799      } //setDocumentElement
 800  
 801      /**
 802      * Appends a node to the childNodes list of the current node
 803      * @param Object The node to be appended
 804      * @return Object The appended node
 805      */
 806      function &appendChild(&$node) {
 807          if ($node->nodeType == DOMIT_ELEMENT_NODE) {
 808              if ($this->documentElement == null) {
 809                  parent::appendChild($node);
 810                  $this->setDocumentElement($node);
 811              }
 812              else {
 813                  //error thrown if documentElement already exists!
 814                  DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
 815                      ('Cannot have more than one root node (documentElement) in a DOMIT_Document.'));
 816              }
 817          }
 818          else {
 819              DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
 820                  ('Cannot add a node of type ' . get_class($node) . ' to a DOMIT_Document.'));
 821          }
 822  
 823          return $node;
 824      } //appendChild
 825  
 826      /**
 827      * Replaces a node with another
 828      * @param Object The new node
 829      * @param Object The old node
 830      * @return Object The new node
 831      */
 832      function &replaceChild(&$newChild, &$oldChild) {
 833              if (($this->documentElement != null) && ($oldChild->uid == $this->documentElement->uid)) {
 834                  if ($node->nodeType == DOMIT_ELEMENT_NODE) {
 835                      //replace documentElement with new node
 836                      $this->setDocumentElement($newChild);
 837                  }
 838                  else {
 839                      DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
 840                          ('Cannot replace Document Element with a node of class ' . get_class($newChild)));
 841                  }
 842              }
 843              else {
 844                  if ($node->nodeType == DOMIT_ELEMENT_NODE) {
 845                      if ($this->documentElement != null) {
 846                          DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
 847                              ('Cannot have more than one root node (documentElement) in a DOMIT_Document.'));
 848                      }
 849                      else {
 850                          parent::replaceChild($newChild, $oldChild);
 851                      }
 852                  }
 853                  else {
 854                      DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
 855                          ('Nodes of class ' . get_class($newChild) . ' cannot be children of a DOMIT_Document.'));
 856                  }
 857              }
 858  
 859          return $newChild;
 860      } //replaceChild
 861  
 862      /**
 863      * Inserts a node to the childNodes list of the current node
 864      * @param Object The node to be inserted
 865      * @param Object The node before which the insertion is to occur
 866      * @return Object The inserted node
 867      */
 868      function &insertBefore(&$newChild, &$refChild) {
 869          $type = $newChild->nodeType;
 870  
 871          if ($type == DOMIT_ELEMENT_NODE) {
 872              if ($this->documentElement == null) {
 873                  parent::insertBefore($newChild, $refChild);
 874                  $this->setDocumentElement($newChild);
 875              }
 876              else {
 877                  //error thrown if documentElement already exists!
 878                  DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
 879                      ('Cannot have more than one root node (documentElement) in a DOMIT_Document.'));
 880              }
 881          }
 882          else {
 883              DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
 884                  ('Cannot insert a node of type ' . get_class($newChild) . ' to a DOMIT_Document.'));
 885          }
 886  
 887          return $newChild;
 888      } //insertBefore
 889  
 890      /**
 891      * Removes a node from the childNodes list of the current node
 892      * @param Object The node to be removed
 893      * @return Object The removed node
 894      */
 895      function &removeChild(&$oldChild) {
 896          if (($this->documentElement != null) && ($oldChild->uid == $this->documentElement->uid)) {
 897              parent::removeChild($oldChild);
 898              $this->documentElement = null;
 899          }
 900          else {
 901              parent::removeChild($oldChild);
 902          }
 903  
 904          $oldChild->clearReferences();
 905          return $oldChild;
 906      } //removeChild
 907  
 908      /**
 909      * Creates a new DOMIT_Lite_Element node
 910      * @param string The tag name of the element
 911      * @return Object The new element
 912      */
 913      function &createElement($tagName) {
 914          $node = new DOMIT_Lite_Element($tagName);
 915          $node->ownerDocument = $this;
 916  
 917          $reference =& $node;
 918          return $node;
 919      } //createElement
 920  
 921      /**
 922      * Creates a new DOMIT_Text node
 923      * @param string The text of the node
 924      * @return Object The new text node
 925      */
 926      function &createTextNode($data) {
 927          $node = new DOMIT_Lite_TextNode($data);
 928          $node->ownerDocument = $this;
 929  
 930          $reference =& $node;
 931          return $reference;
 932      } //createTextNode
 933  
 934      /**
 935      * Creates a new DOMIT_Lite_CDATASection node
 936      * @param string The text of the CDATASection
 937      * @return Object The new CDATASection node
 938      */
 939      function &createCDATASection($data) {
 940          $node = new DOMIT_Lite_CDATASection($data);
 941          $node->ownerDocument = $this;
 942  
 943          return $node;
 944      } //createCDATASection
 945  
 946      /**
 947      * Retrieves a NodeList of child elements with the specified tag name
 948      * @param string The matching element tag name
 949      * @return Object A NodeList of found elements
 950      */
 951      function &getElementsByTagName($tagName) {
 952          $nodeList = new DOMIT_NodeList();
 953  
 954          if ($this->documentElement != null) {
 955              $this->documentElement->getNamedElements($nodeList, $tagName);
 956          }
 957  
 958          return $nodeList;
 959      } //getElementsByTagName
 960  
 961      /**
 962      * Retrieves an element or DOMIT_NodeList of elements corresponding to an Xpath-like expression.
 963      * @param string The query pattern
 964      * @param int If a single node is to be returned (rather than the entire NodeList) the index of that node
 965      * @return mixed A NodeList or single node that matches the pattern
 966      */
 967      function &getElementsByPath($pattern, $nodeIndex = 0) {
 968          require_once (DOMIT_INCLUDE_PATH . 'xml_domit_getelementsbypath.php');
 969  
 970          $gebp = new DOMIT_GetElementsByPath();
 971          $myResponse =& $gebp->parsePattern($this, $pattern, $nodeIndex);
 972  
 973          return $myResponse;
 974      } //getElementsByPath
 975  
 976      /**
 977      * Parses an xml string; first encodes string as UTF-8
 978      * @param string The xml text to be parsed
 979      * @param boolean True if SAXY is to be used instead of Expat
 980      * @param boolean False if CDATA Section are to be generated as Text nodes
 981      * @param boolean True if onLoad is to be called on each node after parsing
 982      * @return boolean True if parsing is successful
 983      */
 984  	function parseXML_utf8($xmlText, $useSAXY = true, $preserveCDATA = true, $fireLoadEvent = false) {
 985          return $this->parseXML(utf8_encode($xmlText), $useSAXY, $preserveCDATA, $fireLoadEvent);
 986      } //parseXML_utf8
 987  
 988      /**
 989      * Parses an xml string
 990      * @param string The xml text to be parsed
 991      * @param boolean True if SAXY is to be used instead of Expat
 992      * @param boolean False if CDATA Section are to be generated as Text nodes
 993      * @param boolean True if onLoad is to be called on each node after parsing
 994      * @return boolean True if parsing is successful
 995      */
 996  	function parseXML($xmlText, $useSAXY = true, $preserveCDATA = true, $fireLoadEvent = false) {
 997          require_once (DOMIT_INCLUDE_PATH . 'xml_domit_utilities.php');
 998  
 999          if ($this->doResolveErrors) {
1000              require_once (DOMIT_INCLUDE_PATH . 'xml_domit_doctor.php');
1001              $xmlText = DOMIT_Doctor::fixAmpersands($xmlText);
1002          }
1003  
1004          if (DOMIT_Utilities::validateXML($xmlText)) {
1005              $domParser = new DOMIT_Lite_Parser();
1006  
1007              if ($useSAXY || (!function_exists('xml_parser_create'))) {
1008                  //use SAXY parser to populate xml tree
1009                  $this->parser = 'SAXY_LITE';
1010                  $success = $domParser->parseSAXY($this, $xmlText, $preserveCDATA, $this->definedEntities);
1011              }
1012              else {
1013                  //use Expat parser to populate xml tree
1014                  $this->parser = 'EXPAT';
1015                  $success = $domParser->parse($this, $xmlText, $preserveCDATA);
1016              }
1017  
1018              if ($fireLoadEvent && ($this->documentElement != null)) $this->load($this->documentElement);
1019  
1020              return $success;
1021          }
1022  
1023          return false;
1024      } //parseXML
1025  
1026      /**
1027      * Parses an xml file; first encodes text as UTF-8
1028      * @param string The xml file to be parsed
1029      * @param boolean True if SAXY is to be used instead of Expat
1030      * @param boolean False if CDATA Section are to be generated as Text nodes
1031      * @param boolean True if onLoad is to be called on each node after parsing
1032      * @return boolean True if parsing is successful
1033      */
1034  	function loadXML_utf8($filename, $useSAXY = true, $preserveCDATA = true, $fireLoadEvent = false) {
1035          $xmlText = $this->getTextFromFile($filename);
1036          return $this->parseXML_utf8($xmlText, $useSAXY, $preserveCDATA, $fireLoadEvent);
1037      } //loadXML_utf8
1038  
1039      /**
1040      * Parses an xml file
1041      * @param string The xml file to be parsed
1042      * @param boolean True if SAXY is to be used instead of Expat
1043      * @param boolean False if CDATA Section are to be generated as Text nodes
1044      * @param boolean True if onLoad is to be called on each node after parsing
1045      * @return boolean True if parsing is successful
1046      */
1047  	function loadXML($filename, $useSAXY = true, $preserveCDATA = true, $fireLoadEvent = false) {
1048          $xmlText = $this->getTextFromFile($filename);
1049          return $this->parseXML($xmlText, $useSAXY, $preserveCDATA, $fireLoadEvent);
1050      } //loadXML
1051  
1052      /**
1053      * Establishes a connection, given an url
1054      * @param string The url of the data
1055      */
1056  	function establishConnection($url) {
1057          require_once (DOMIT_INCLUDE_PATH . 'php_http_client_generic.php');
1058  
1059          $host = php_http_connection::formatHost($url);
1060          $host = substr($host, 0, strpos($host, '/'));
1061  
1062          $this->setConnection($host);
1063      } //establishConnection
1064  
1065      /**
1066      * Retrieves text from a file
1067      * @param string The file path
1068      * @return string The text contained in the file
1069      */
1070  	function getTextFromFile($filename) {
1071          if ($this->doUseHTTPClient && (substr($filename, 0, 5) == 'http:')) {
1072              $this->establishConnection($filename);
1073          }
1074  
1075          if ($this->httpConnection != null) {
1076              $response =& $this->httpConnection->get($filename);
1077              $this->httpConnection->disconnect();
1078              return $response->getResponse();
1079          }
1080          else if (function_exists('file_get_contents')) {
1081              //if (file_exists($filename)) {
1082                  return file_get_contents($filename);
1083              //}
1084          }
1085          else {
1086              require_once (DOMIT_INCLUDE_PATH . 'php_file_utilities.php');
1087  
1088              $fileContents =& php_file_utilities::getDataFromFile($filename, 'r');
1089              return $fileContents;
1090          }
1091  
1092          return '';
1093      } //getTextFromFile
1094  
1095      /**
1096      * Saves the current DOM document as an xml file; first encodes text as UTF-8
1097      * @param string The path of the xml file
1098      * @param boolean True if xml text is to be normalized before saving
1099      * @return boolean True if save is successful
1100      */
1101  	function saveXML_utf8($filename, $normalized=false) {
1102          if ($normalized) {
1103              $stringRep = $this->toNormalizedString(false, true); //param 2 is $subEntities
1104          }
1105          else {
1106              $stringRep = $this->toString(false, true);
1107          }
1108  
1109          return $this->saveTextToFile($filename, utf8_encode($stringRep));
1110      } //saveXML_utf8
1111  
1112      /**
1113      * Saves the current DOM document as an xml file
1114      * @param string The path of the xml file
1115      * @param boolean True if xml text is to be normalized before saving
1116      * @return boolean True if save is successful
1117      */
1118  	function saveXML($filename, $normalized=false) {
1119          if ($normalized) {
1120              $stringRep = $this->toNormalizedString(false, true);
1121          }
1122          else {
1123              $stringRep = $this->toString(false, true);
1124          }
1125          if ($this->xmlDeclaration) {
1126              $stringRep = $this->xmlDeclaration . "\n" . $stringRep;
1127          }
1128          return $this->saveTextToFile($filename, $stringRep);
1129      } //saveXML
1130  
1131      /**
1132      * Saves text to a file
1133      * @param string The file path
1134      * @param string The text to be saved
1135      * @return boolean True if the save is successful
1136      */
1137  	function saveTextToFile($filename, $text) {
1138          if (function_exists('file_put_contents')) {
1139              file_put_contents($filename, $text);
1140          }
1141          else {
1142              require_once (DOMIT_INCLUDE_PATH . 'php_file_utilities.php');
1143              php_file_utilities::putDataToFile($filename, $text, 'w');
1144          }
1145  
1146          return (file_exists($filename) && is_writable($filename));
1147      } //saveTextToFile
1148  
1149      /**
1150      * Indicates the SAX parser used to parse the current document
1151      * @return string Either "SAXY_LITE" or "EXPAT"
1152      */
1153  	function parsedBy() {
1154          return $this->parser;
1155      } //parsedBy
1156  
1157      /**
1158      * Returns the concatented text of the current node and its children
1159      * @return string The concatented text of the current node and its children
1160      */
1161  	function getText() {
1162          if ($this->documentElement != null) {
1163              $root =& $this->documentElement;
1164              return $root->getText();
1165          }
1166  
1167          return '';
1168      } //getText
1169  
1170      /**
1171      * Returns the doctype text
1172      * @return string The doctype text, or an emty string
1173      */
1174  	function getDocType() {
1175          return $this->doctype;
1176      } //getDocType
1177  
1178      /**
1179      * Returns the xml declaration text
1180      * @return mixed The xml declaration text, or an empty string
1181      */
1182  	function getXMLDeclaration() {
1183          return $this->xmlDeclaration;
1184      } //getXMLDeclaration
1185  
1186      /**
1187      * Returns the xml declaration text
1188      * @return mixed The xml declaration text, or an empty string
1189      */
1190  	function setXMLDeclaration( $decl ) {
1191          $this->xmlDeclaration = $decl;
1192      } //setXMLDeclaration
1193  
1194      /**
1195      * Returns a reference to the DOMIT_DOMImplementation object
1196      * @return Object A reference to the DOMIT_DOMImplementation object
1197      */
1198      function &getDOMImplementation() {
1199          return $this->implementation;
1200      } //getDOMImplementation
1201  
1202      /**
1203      * Manages the firing of the onLoad() event
1204      * @param Object The parent node of the current recursion
1205      */
1206  	function load(&$contextNode) {
1207          $total = $contextNode->childCount;
1208  
1209          for ($i = 0; $i < $total; $i++) {
1210              $currNode =& $contextNode->childNodes[$i];
1211              $currNode->ownerDocument->load($currNode);
1212          }
1213  
1214          $contextNode->onLoad();
1215      } //load
1216  
1217      /**
1218      * Returns the current version of DOMIT! Lite
1219      * @return Object The current version of DOMIT! Lite
1220      */
1221  	function getVersion() {
1222          return DOMIT_LITE_VERSION;
1223      } //getVersion
1224  
1225      /**
1226      * Appends an array of entity mappings to the existing translation table
1227      *
1228      * Intended mainly to facilitate the conversion of non-ASCII entities into equivalent characters
1229      *
1230      * @param array A list of entity mappings in the format: array('&amp;' => '&');
1231      */
1232  	function appendEntityTranslationTable($table) {
1233          $this->definedEntities = $table;
1234  
1235          global $DOMIT_defined_entities_flip;
1236          $DOMIT_defined_entities_flip = array_flip($table);
1237      } //appendEntityTranslationTable
1238  
1239      /**
1240      * Generates an array representation of the node and its children
1241      * @return Array A representation of the node and its children
1242      */
1243  	function toArray() {
1244          $arReturn = array($this->nodeName => array());
1245          $total = $this->childCount;
1246  
1247          for ($i = 0; $i < $total; $i++) {
1248              $arReturn[$this->nodeName][$i] = $this->childNodes[$i]->toArray();
1249          }
1250  
1251          return $arReturn;
1252      } //toArray
1253  
1254      /**
1255      * Copies a node and/or its children
1256      * @param boolean True if all child nodes are also to be cloned
1257      * @return Object A copy of the node and/or its children
1258      */
1259      function &cloneNode($deep = false) {
1260          $className = get_class($this);
1261          $clone = new $className($this->nodeName);
1262  
1263          if ($deep) {
1264              $total = $this->childCount;
1265  
1266              for ($i = 0; $i < $total; $i++) {
1267                  $currentChild =& $this->childNodes[$i];
1268                  $clone->appendChild($currentChild->cloneNode($deep));
1269              }
1270          }
1271  
1272          return $clone;
1273      } //cloneNode
1274  
1275      /**
1276      * Generates a string representation of the node and its children
1277      * @param boolean True if HTML readable output is desired
1278      * @param boolean True if illegal xml characters in text nodes and attributes should be converted to entities
1279      * @return string The string representation
1280      */
1281  	function toString($htmlSafe = false, $subEntities = false) {
1282          $result = '';
1283          $total = $this->childCount;
1284  
1285          for ($i = 0; $i < $total; $i++) {
1286              $result .= $this->childNodes[$i]->toString(false, $subEntities);
1287          }
1288  
1289          if ($htmlSafe) $result = $this->forHTML($result);
1290  
1291          return $result;
1292      } //toString
1293  } //DOMIT_Lite_Document
1294  
1295  /**
1296  * A class representing the DOM Element
1297  *
1298  * @package domit-xmlparser
1299  * @subpackage domit-xmlparser-lite
1300  * @author John Heinstein <johnkarl@nbnet.nb.ca>
1301  */
1302  class DOMIT_Lite_Element extends DOMIT_Lite_ChildNodes_Interface {
1303      /**
1304      * DOM Element constructor
1305      * @param string The tag name of the element
1306      */
1307  	function DOMIT_Lite_Element($tagName) {
1308          $this->_constructor();
1309          $this->nodeType = DOMIT_ELEMENT_NODE;
1310          $this->nodeName = $tagName;
1311          $this->attributes = array();
1312          $this->childNodes = array();
1313      } //DOMIT_Lite_Element
1314  
1315      /**
1316      * Returns the tag name of the element
1317      * @return string The tag name of the element
1318      */
1319  	function getTagName() {
1320          return $this->nodeName;
1321      } //getTagName
1322  
1323      /**
1324      * Adds elements with the specified tag name to a NodeList collection
1325      * @param Object The NodeList collection
1326      * @param string The tag name of matching elements
1327      */
1328  	function getNamedElements(&$nodeList, $tagName) {
1329          if (($this->nodeName == $tagName) || ($tagName == '*')) {
1330              $nodeList->appendNode($this);
1331          }
1332  
1333          $total = $this->childCount;
1334  
1335          for ($i = 0; $i < $total; $i++) {
1336              $this->childNodes[$i]->getNamedElements($nodeList, $tagName);
1337          }
1338      } //getNamedElements
1339  
1340      /**
1341      * Returns the concatented text of the current node and its children
1342      * @return string The concatented text of the current node and its children
1343      */
1344  	function getText() {
1345          $text = '';
1346          $numChildren = $this->childCount;
1347  
1348          for ($i = 0; $i < $numChildren; $i++) {
1349              $child =& $this->childNodes[$i];
1350              $text .= $child->getText();
1351          }
1352  
1353          return $text;
1354      } //getText
1355  
1356      /**
1357      * If a child text node exists, sets the nodeValue to $data. A child text node is created if none exists
1358      * @param string The text data of the node
1359      */
1360  	function setText($data) {
1361          switch ($this->childCount) {
1362              case 1:
1363                  if ($this->firstChild->nodeType == DOMIT_TEXT_NODE) {
1364                      $this->firstChild->setText($data);
1365                  }
1366                  break;
1367  
1368              case 0:
1369                  $childTextNode =& $this->ownerDocument->createTextNode($data);
1370                  $this->appendChild($childTextNode);
1371                  break;
1372  
1373              default:
1374                  //do nothing. Maybe throw error???
1375          }
1376      } //setText
1377  
1378      /**
1379      * Retrieves a NodeList of child elements with the specified tag name
1380      * @param string The matching element tag name
1381      * @return Object A NodeList of found elements
1382      */
1383      function &getElementsByTagName($tagName) {
1384          $nodeList = new DOMIT_NodeList();
1385          $this->getNamedElements($nodeList, $tagName);
1386  
1387          return $nodeList;
1388      } //getElementsByTagName
1389  
1390      /**
1391      * Retrieves an element or DOMIT_NodeList of elements corresponding to an Xpath-like expression.
1392      * @param string The query pattern
1393      * @param int If a single node is to be returned (rather than the entire NodeList) the index of that node
1394      * @return mixed A NodeList or single node that matches the pattern
1395      */
1396      function &getElementsByPath($pattern, $nodeIndex = 0) {
1397          require_once (DOMIT_INCLUDE_PATH . 'xml_domit_getelementsbypath.php');
1398  
1399          $gebp = new DOMIT_GetElementsByPath();
1400          $myResponse = $gebp->parsePattern($this, $pattern, $nodeIndex);
1401  
1402          return $myResponse;
1403      } //getElementsByPath
1404  
1405      /**
1406      * Gets the value of the specified attribute, if it exists
1407      * @param string The attribute name
1408      * @return string The attribute value
1409      */
1410  	function getAttribute($name) {
1411          if ($this->hasAttribute($name)) {
1412              return $this->attributes[$name];
1413          }
1414          else {
1415              /*
1416              DOMIT_DOMException::raiseException(DOMIT_NOT_FOUND_ERR,
1417              ('No attribute named ' . $name . 'exists.'));
1418              */
1419              // Joomla! hack
1420              return null;
1421          }
1422      } //getAttribute
1423  
1424      /**
1425      * Sets the value of the specified attribute; creates a new attribute if one doesn't exist
1426      * @param string The attribute name
1427      * @param string The desired attribute value
1428      */
1429  	function setAttribute($name, $value) {
1430          $this->attributes[$name] = $value;
1431      } //setAttribute
1432  
1433      /**
1434      * Removes the specified attribute
1435      * @param string The name of the attribute to be removed
1436      */
1437  	function removeAttribute($name) {
1438          if ($this->hasAttribute($name)) {
1439              unset($this->attributes[$name]);
1440          }
1441      } //removeAttribute
1442  
1443      /**
1444      * Determines whether an attribute with the specified name exists
1445      * @param string The name of the attribute
1446      * @return boolean True if the attribute exists
1447      */
1448  	function hasAttribute($name) {
1449          return isset($this->attributes[$name]);
1450      } //hasAttribute
1451  
1452      /**
1453      * Collapses adjacent text nodes in entire element subtree
1454      */
1455  	function normalize() {
1456          if ($this->hasChildNodes()) {
1457              $currNode =& $this->childNodes[0];
1458  
1459              while ($currNode->nextSibling != null) {
1460                  $nextNode =& $currNode->nextSibling;
1461  
1462                  if (($currNode->nodeType == DOMIT_TEXT_NODE) &&
1463                      ($nextNode->nodeType == DOMIT_TEXT_NODE)) {
1464                      $currNode->nodeValue .= $nextNode->nodeValue;
1465                      $this->removeChild($nextNode);
1466                  }
1467                  else {
1468                      $currNode->normalize();
1469                  }
1470  
1471                  if ($currNode->nextSibling != null) {
1472                      $currNode =& $currNode->nextSibling;
1473                  }
1474              }
1475          }
1476      } //normalize
1477  
1478      /**
1479      * Generates an array representation of the node and its children
1480      * @return Array A representation of the node and its children
1481      */
1482  	function toArray() {
1483          $arReturn = array($this->nodeName => array("attributes" => $this->attributes));
1484          $total = $this->childCount;
1485  
1486          for ($i = 0; $i < $total; $i++) {
1487              $arReturn[$this->nodeName][$i] = $this->childNodes[$i]->toArray();
1488          }
1489  
1490          return $arReturn;
1491      } //toArray
1492  
1493      /**
1494      * Copies a node and/or its children
1495      * @param boolean True if all child nodes are also to be cloned
1496      * @return Object A copy of the node and/or its children
1497      */
1498      function &cloneNode($deep = false) {
1499          $className = get_class($this);
1500          $clone = new $className($this->nodeName);
1501  
1502          $clone->attributes = $this->attributes;
1503  
1504          if ($deep) {
1505              $total = $this->childCount;
1506  
1507              for ($i = 0; $i < $total; $i++) {
1508                  $currentChild =& $this->childNodes[$i];
1509                  $clone->appendChild($currentChild->cloneNode($deep));
1510              }
1511          }
1512  
1513          return $clone;
1514      } //cloneNode
1515  
1516      /**
1517      * Generates a string representation of the node and its children
1518      * @param boolean True if HTML readable output is desired
1519      * @param boolean True if illegal xml characters in text nodes and attributes should be converted to entities
1520      * @return string The string representation
1521      */
1522  	function toString($htmlSafe = false, $subEntities = false) {
1523          require_once (DOMIT_INCLUDE_PATH . 'xml_domit_utilities.php');
1524          global $DOMIT_defined_entities_flip;
1525  
1526          $result = '<' . $this->nodeName;
1527  
1528          //get attributes
1529          foreach ($this->attributes as $key => $value) {
1530              $result .= ' ' . $key . '="';
1531              $result .= $subEntities ? DOMIT_Utilities::convertEntities($value,
1532                              $DOMIT_defined_entities_flip) : $value;
1533              $result .= '"';
1534          }
1535  
1536          //get children
1537          $myNodes =& $this->childNodes;
1538          $total = count($myNodes);
1539  
1540          if ($total != 0) {
1541              $result .= '>';
1542  
1543              for ($i = 0; $i < $total; $i++) {
1544                  $child =& $myNodes[$i];
1545                  $result .= $child->toString(false, $subEntities);
1546              }
1547  
1548              $result .= '</' . $this->nodeName . '>';
1549          }
1550          else {
1551              if ($this->ownerDocument->doExpandEmptyElementTags) {
1552                  if (in_array($this->nodeName, $this->ownerDocument->expandEmptyElementExceptions)) {
1553                      $result .= ' />';
1554                  }
1555                  else {
1556                      $result .= '></' . $this->nodeName . '>';
1557                  }
1558              }
1559              else {
1560                  if (in_array($this->nodeName, $this->ownerDocument->expandEmptyElementExceptions)) {
1561                      $result .= '></' . $this->nodeName . '>';
1562                  }
1563                  else {
1564                      $result .= ' />';
1565                  }
1566              }
1567          }
1568  
1569          if ($htmlSafe) $result = $this->forHTML($result);
1570  
1571          return $result;
1572      } //toString
1573  } //DOMIT_Lite_Element
1574  
1575  /**
1576  * A class representing the DOM Text Node
1577  *
1578  * @package domit-xmlparser
1579  * @subpackage domit-xmlparser-lite
1580  * @author John Heinstein <johnkarl@nbnet.nb.ca>
1581  */
1582  class DOMIT_Lite_TextNode extends DOMIT_Lite_Node {
1583      /**
1584      * DOM Text Node constructor
1585      * @param string The text of the node
1586      */
1587  	function DOMIT_Lite_TextNode($data) {
1588          $this->_constructor();
1589          $this->nodeType = DOMIT_TEXT_NODE;
1590          $this->nodeName = '#text';
1591          $this->setText($data);
1592      } //DOMIT_Lite_TextNode
1593  
1594      /**
1595      * Returns the text contained in the current node
1596      * @return string The text of the current node
1597      */
1598  	function getText() {
1599          return $this->nodeValue;
1600      } //getText
1601  
1602       /**
1603      * Sets the text contained in the current node to $data.
1604      * @param string The text data of the node
1605      */
1606  	function setText($data) {
1607          $this->nodeValue = $data;
1608      } //setText
1609  
1610      /**
1611      * Generates an array representation of the node and its children
1612      * @return Array A representation of the node and its children
1613      */
1614  	function toArray() {
1615          return $this->toString();
1616      } //toArray
1617  
1618      /**
1619      * Copies a node and/or its children
1620      * @param boolean True if all child nodes are also to be cloned
1621      * @return Object A copy of the node and/or its children
1622      */
1623      function &cloneNode($deep = false) {
1624          $className = get_class($this);
1625          $clone = new $className($this->nodeValue);
1626  
1627          return $clone;
1628      } //cloneNode
1629  
1630      /**
1631      * Generates a string representation of the node and its children
1632      * @param boolean True if HTML readable output is desired
1633      * @param boolean True if illegal xml characters should be converted to entities
1634      * @return string The string representation
1635      */
1636  	function toString($htmlSafe = false, $subEntities = false) {
1637          require_once (DOMIT_INCLUDE_PATH . 'xml_domit_utilities.php');
1638          global $DOMIT_defined_entities_flip;
1639  
1640          $result = $subEntities ? DOMIT_Utilities::convertEntities($this->nodeValue,
1641                          $DOMIT_defined_entities_flip) : $this->nodeValue;
1642  
1643          if ($htmlSafe) $result = $this->forHTML($result);
1644  
1645          return $result;
1646      } //toString
1647  } //DOMIT_Lite_TextNode
1648  
1649  /**
1650  * A class representing the DOM CDATA Section
1651  *
1652  * @package domit-xmlparser
1653  * @subpackage domit-xmlparser-lite
1654  * @author John Heinstein <johnkarl@nbnet.nb.ca>
1655  */
1656  class DOMIT_Lite_CDATASection extends DOMIT_Lite_TextNode {
1657      /**
1658      * DOM CDATA Section node constructor
1659      * @param string The text of the node
1660      */
1661  	function DOMIT_Lite_CDATASection($data) {
1662          $this->_constructor();
1663          $this->nodeType = DOMIT_CDATA_SECTION_NODE;
1664          $this->nodeName = '#cdata-section';
1665          $this->setText($data);
1666      } //DOMIT_Lite_CDATASection
1667  
1668      /**
1669      * Generates a string representation of the node and its children
1670      * @param boolean True if HTML readable output is desired
1671      * @param boolean True if illegal xml characters should be converted to entities
1672      * @return string The string representation
1673      */
1674  	function toString($htmlSafe = false, $subEntities = false) {
1675          $result = '<![CDATA[';
1676          $result .= $subEntities ? str_replace("]]>", "]]&gt;", $this->nodeValue) :
1677                                   $this->nodeValue;
1678          $result .= ']]>';
1679  
1680          if ($htmlSafe) $result = $this->forHTML($result);
1681  
1682          return $result;
1683      } //toString
1684  } //DOMIT_Lite_CDATASection
1685  
1686  /**
1687  * Manages the generation of a DOMIT! document from SAX events
1688  *
1689  * @package domit-xmlparser
1690  * @subpackage domit-xmlparser-lite
1691  * @author John Heinstein <johnkarl@nbnet.nb.ca>
1692  */
1693  class DOMIT_Lite_Parser {
1694      /** @var Object A reference to the resulting xmldoc */
1695      var $xmlDoc = null;
1696      /** @var Object A reference to the current node in the parsing process */
1697      var $currentNode = null;
1698      /** @var Object A reference to the last child in the parsing process */
1699      var $lastChild = null;
1700      /** @var boolean True if currently parsing a CDATA Section */
1701      var $inCDATASection = false; //flag for Expat
1702      /** @var boolean True if currently parsing a Text node */
1703      var $inTextNode = false;
1704      /** @var boolean True is CDATA Section nodes are not to be converted into Text nodes */
1705      var $preserveCDATA;
1706      /** @var string A container for holding the currently parsed text data */
1707      var $parseContainer = '';
1708      /** @var string The current docutype text */
1709      var $parseItem = '';
1710  
1711      /**
1712      * Parses xml text using Expat
1713      * @param Object A reference to the DOM document that the xml is to be parsed into
1714      * @param string The text to be parsed
1715      * @param boolean True if CDATA Section nodes are not to be converted into Text nodes
1716      * @return boolean True if the parsing is successful
1717      */
1718  	function parse (&$myXMLDoc, $xmlText, $preserveCDATA = true) {
1719          $this->xmlDoc =& $myXMLDoc;
1720          $this->lastChild =& $this->xmlDoc;
1721  
1722          $this->preserveCDATA = $preserveCDATA;
1723  
1724          //create instance of expat parser (should be included in php distro)
1725          if (version_compare(phpversion(), '5.0', '<=')) {
1726              $parser = xml_parser_create('');
1727          }
1728          else {
1729              $parser = xml_parser_create();
1730          }
1731  
1732          //set handlers for SAX events
1733          xml_set_object($parser, $this);
1734          xml_set_element_handler($parser, 'startElement', 'endElement');
1735          xml_set_character_data_handler($parser, 'dataElement');
1736          xml_set_default_handler($parser, 'defaultDataElement');
1737          xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
1738  
1739          if (!$this->xmlDoc->preserveWhitespace) {
1740              xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
1741          }
1742          else {
1743              xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
1744          }
1745  
1746          //parse out whitespace -  (XML_OPTION_SKIP_WHITE = 1 does not
1747          //seem to work consistently across versions of PHP and Expat
1748          if (!$this->xmlDoc->preserveWhitespace) {
1749              $xmlText = preg_replace('#>' . "[[:space:]]+" . '<#i' , '><', $xmlText);
1750          }
1751  
1752          $success = xml_parse($parser, $xmlText);
1753  
1754          $this->xmlDoc->errorCode = xml_get_error_code($parser);
1755          $this->xmlDoc->errorString = xml_error_string($this->xmlDoc->errorCode);
1756  
1757          xml_parser_free($parser);
1758  
1759          return $success;
1760      } //parse
1761  
1762      /**
1763      * Parses xml text using SAXY
1764      * @param Object A reference to the DOM document that the xml is to be parsed into
1765      * @param string The text to be parsed
1766      * @param boolean True if CDATA Section nodes are not to be converted into Text nodes
1767      * @return boolean True if the parsing is successful
1768      */
1769  	function parseSAXY(&$myXMLDoc, $xmlText, $preserveCDATA, $definedEntities) {
1770          require_once (DOMIT_INCLUDE_PATH . 'xml_saxy_lite_parser.php');
1771  
1772          $this->xmlDoc =& $myXMLDoc;
1773          $this->lastChild =& $this->xmlDoc;
1774  
1775          //create instance of SAXY parser
1776          $parser = new SAXY_Lite_Parser();
1777          $parser->appendEntityTranslationTable($definedEntities);
1778  
1779          //not yet implemented in SAXY!!!
1780          $parser->preserveWhitespace = $this->xmlDoc->preserveWhitespace;
1781  
1782          $parser->xml_set_element_handler(array(&$this, 'startElement'), array(&$this, 'endElement'));
1783          $parser->xml_set_character_data_handler(array(&$this, 'dataElement'));
1784  
1785          if ($preserveCDATA) {
1786              $parser->xml_set_cdata_section_handler(array(&$this, 'cdataElement'));
1787          }
1788  
1789          $success = $parser->parse($xmlText);
1790  
1791          $this->xmlDoc->errorCode = $parser->xml_get_error_code();
1792          $this->xmlDoc->errorString = $parser->xml_error_string($this->xmlDoc->errorCode);
1793  
1794          return $success;
1795      } //parseSAXY
1796  
1797      /**
1798      * Generates and appends a new text node from the parseContainer text
1799      */
1800  	function dumpTextNode() {
1801          //traps for mixed content
1802          $currentNode =& $this->xmlDoc->createTextNode($this->parseContainer);
1803          $this->lastChild->appendChild($currentNode);
1804          $this->inTextNode = false;
1805          $this->parseContainer = '';
1806      } //dumpTextNode
1807  
1808      /**
1809      * Catches a start element event and processes the data
1810      * @param Object A reference to the current SAX parser
1811      * @param string The tag name of the current element
1812      * @param Array An array of the element attributes
1813      */
1814  	function startElement(&$parser, $name, $attrs) {
1815          if ($this->inTextNode) {
1816              $this->dumpTextNode();
1817          }
1818  
1819          $currentNode =& $this->xmlDoc->createElement($name);
1820          $currentNode->attributes = $attrs;
1821          $this->lastChild->appendChild($currentNode);
1822          $this->lastChild =& $currentNode;
1823      } //startElement
1824  
1825      /**
1826      * Catches an end element event and processes the data
1827      * @param Object A reference to the current SAX parser
1828      * @param string The tag name of the current element
1829      */
1830  	function endElement(&$parser, $name) {
1831          if ($this->inTextNode) {
1832              $this->dumpTextNode();
1833          }
1834  
1835          $this->lastChild =& $this->lastChild->parentNode;
1836      } //endElement
1837  
1838      /**
1839      * Catches a data event and processes the text
1840      * @param Object A reference to the current SAX parser
1841      * @param string The current text data
1842      */
1843  	function dataElement(&$parser, $data) {
1844          if (!$this->inCDATASection) $this->inTextNode = true;
1845  
1846          $this->parseContainer .= $data;
1847      } //dataElement
1848  
1849      /**
1850      * Catches a CDATA Section event and processes the text
1851      * @param Object A reference to the current SAX parser
1852      * @param string The current text data
1853      */
1854  	function cdataElement(&$parser, $data) {
1855          $currentNode =& $this->xmlDoc->createCDATASection($data);
1856  
1857          $this->lastChild->appendChild($currentNode);
1858      } //cdataElement
1859  
1860      /**
1861      * Catches a default data event and processes the data
1862      * @param Object A reference to the current SAX parser
1863      * @param string The current data
1864      */
1865  	function defaultDataElement(&$parser, $data) {
1866          if (strlen($data) > 2){
1867              $pre = strtoupper(substr($data, 0, 3));
1868  
1869              switch ($pre) {
1870                  case '<![': //cdata section coming
1871                      if ($this->preserveCDATA) {
1872                          $this->inCDATASection = true;
1873                      }
1874                      break;
1875                  case ']]>': //cdata remnant - ignore
1876                      if ($this->preserveCDATA) {
1877                          $currentNode =& $this->xmlDoc->createCDATASection($this->parseContainer);
1878                          $this->lastChild->appendChild($currentNode);
1879                          $this->inCDATASection = false;
1880                          $this->parseContainer = '';
1881                      }
1882                      else {
1883                          $this->dumpTextNode();
1884                      }
1885  
1886                      break;
1887              }
1888          }
1889      } //defaultDataElement
1890  } //DOMIT_Lite_Parser
1891  
1892  ?>


Generated: Wed Mar 28 15:54:07 2012 Cross-referenced by PHPXref 0.7.1