[ Index ]
 

Code source de Joomla 1.0.13

Accédez au Source d'autres logiciels libres

title

Body

[fermer]

/includes/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              return null;
 584          }
 585  
 586          return $nodelist;
 587      } //getElementsByAttribute
 588  
 589      /**
 590      * Searches the element tree for an element with the specified attribute name and value.
 591      * @param object The node list of found elements
 592      * @param string The value of the attribute
 593      * @param string The name of the attribute
 594      * @param boolean True if the first found node is to be returned as a node instead of a nodelist
 595      * @param boolean True if uid is to be considered an attribute
 596      * @param boolean True the node has been found
 597      */
 598  	function _getElementsByAttribute(&$nodelist, $attrName, $attrValue,
 599                          $returnFirstFoundNode, $treatUIDAsAttribute, $foundNode = false) {
 600          if (!($foundNode && $returnFirstFoundNode)) {
 601              if (($this->getAttribute($attrName) == $attrValue) ||
 602                  ($treatUIDAsAttribute && ($attrName == 'uid') && ($this->uid == $attrValue))) {
 603                  $nodelist->appendNode($this);
 604                  $foundNode = true;
 605                  if ($returnFirstFoundNode) return;
 606              }
 607  
 608              $total = $this->childCount;
 609  
 610              for ($i = 0; $i < $total; $i++) {
 611                  $currNode =& $this->childNodes[$i];
 612  
 613                  if ($currNode->nodeType == DOMIT_ELEMENT_NODE) {
 614                      $currNode->_getElementsByAttribute($nodelist,
 615                                      $attrName, $attrValue, $returnFirstFoundNode,
 616                                      $treatUIDAsAttribute, $foundNode);
 617                  }
 618              }
 619          }
 620      } //_getElementsByAttribute
 621  } //DOMIT_Lite_ChildNodes_Interface
 622  
 623  /**
 624  * A class representing the DOM Document
 625  *
 626  * @package domit-xmlparser
 627  * @subpackage domit-xmlparser-lite
 628  * @author John Heinstein <johnkarl@nbnet.nb.ca>
 629  */
 630  class DOMIT_Lite_Document extends DOMIT_Lite_ChildNodes_Interface {
 631      /** @var string The xml declaration text */
 632      var $xmlDeclaration;
 633      /** @var string The doctype text */
 634      var $doctype;
 635      /** @var Object A reference to the root node of the DOM document */
 636      var $documentElement;
 637      /** @var string The parser used to process the DOM document, either "EXPAT" or "SAXY_LITE" */
 638      var $parser;
 639      /** @var Object A reference to the DOMIT_DOMImplementation object */
 640      var $implementation;
 641      /** @var Array User defined translation table for XML entities */
 642      var $definedEntities = array();
 643      /** @var boolean If true, loadXML or parseXML will attempt to detect and repair invalid xml */
 644      var $doResolveErrors = false;
 645      /** @var boolean True if whitespace is to be preserved during parsing */
 646      var $preserveWhitespace = false;
 647      /** @var boolean If true, elements tags will be rendered to string as <element></element> rather than <element/> */
 648      var $doExpandEmptyElementTags = false;
 649      /** @var array A list of exceptions to the empty element expansion rule */
 650      var $expandEmptyElementExceptions = array();
 651      /** @var int The error code returned by the SAX parser */
 652      var $errorCode = 0;
 653      /** @var string The error string returned by the SAX parser */
 654      var $errorString = '';
 655      /** @var object A reference to a http connection or proxy server, if one is required */
 656      var $httpConnection = null;
 657      /** @var boolean True if php_http_client_generic is to be used instead of PHP get_file_contents to retrieve xml data */
 658      var $doUseHTTPClient = false;
 659  
 660      /**
 661      * DOM Document constructor
 662      */
 663  	function DOMIT_Lite_Document() {
 664          $this->_constructor();
 665          $this->xmlDeclaration = '';
 666          $this->doctype = '';
 667          $this->documentElement = null;
 668          $this->nodeType = DOMIT_DOCUMENT_NODE;
 669          $this->nodeName = '#document';
 670          $this->ownerDocument =& $this;
 671          $this->parser = '';
 672          $this->implementation = new DOMIT_DOMImplementation();
 673      } //DOMIT_Lite_Document
 674  
 675      /**
 676      * Specifies whether DOMIT! Lite will try to fix invalid XML before parsing begins
 677      * @param boolean True if errors are to be resolved
 678      */
 679  	function resolveErrors($truthVal) {
 680          $this->doResolveErrors = $truthVal;
 681      } //resolveErrors
 682  
 683      /**
 684      * Specifies the parameters of the http conection used to obtain the xml data
 685      * @param string The ip address or domain name of the connection
 686      * @param string The path of the connection
 687      * @param int The port that the connection is listening on
 688      * @param int The timeout value for the connection
 689      * @param string The user name, if authentication is required
 690      * @param string The password, if authentication is required
 691      */
 692  	function setConnection($host, $path = '/', $port = 80, $timeout = 0, $user = null, $password = null) {
 693          require_once (DOMIT_INCLUDE_PATH . 'php_http_client_generic.php');
 694  
 695          $this->httpConnection = new php_http_client_generic($host, $path, $port, $timeout, $user, $password);
 696      } //setConnection
 697  
 698      /**
 699      * Specifies whether DOMIT! preserves whitespace when parsing
 700      * @param boolean True if whitespace is to be preserved
 701      */
 702  	function preserveWhitespace($truthVal) {
 703          $this->preserveWhitespace = $truthVal;
 704      } //preserveWhitespace
 705  
 706      /**
 707      * Specifies basic authentication for an http connection
 708      * @param string The user name
 709      * @param string The password
 710      */
 711  	function setAuthorization($user, $password) {
 712          $this->httpConnection->setAuthorization($user, $password);
 713      } //setAuthorization
 714  
 715      /**
 716      * Specifies that a proxy is to be used to obtain the xml data
 717      * @param string The ip address or domain name of the proxy
 718      * @param string The path to the proxy
 719      * @param int The port that the proxy is listening on
 720      * @param int The timeout value for the connection
 721      * @param string The user name, if authentication is required
 722      * @param string The password, if authentication is required
 723      */
 724  	function setProxyConnection($host, $path = '/', $port = 80, $timeout = 0, $user = null, $password = null) {
 725          require_once (DOMIT_INCLUDE_PATH . 'php_http_proxy.php');
 726  
 727          $this->httpConnection = new php_http_proxy($host, $path, $port, $timeout, $user, $password);
 728      } //setProxyConnection
 729  
 730      /**
 731      * Specifies basic authentication for the proxy
 732      * @param string The user name
 733      * @param string The password
 734      */
 735  	function setProxyAuthorization($user, $password) {
 736          $this->httpConnection->setProxyAuthorization($user, $password);
 737      } //setProxyAuthorization
 738  
 739      /**
 740      * Specifies whether an HTTP client should be used to establish a connection
 741      * @param boolean True if an HTTP client is to be used to establish the connection
 742      */
 743  	function useHTTPClient($truthVal) {
 744          $this->doUseHTTPClient = $truthVal;
 745      } //useHTTPClient
 746  
 747      /**
 748      * Returns the error code from the underlying SAX parser
 749      * @return int The error code
 750      */
 751  	function getErrorCode() {
 752          return $this->errorCode;
 753      } //getErrorCode
 754  
 755      /**
 756      * Returns the error string from the underlying SAX parser
 757      * @return string The error string
 758      */
 759  	function getErrorString() {
 760          return $this->errorString;
 761      } //getErrorString
 762  
 763      /**
 764      * Specifies whether elements tags will be rendered to string as <element></element> rather than <element/>
 765      * @param boolean True if the expanded form is to be used
 766      * @param mixed An array of tag names that should be excepted from expandEmptyElements rule (optional)
 767      */
 768  	function expandEmptyElementTags($truthVal, $expandEmptyElementExceptions = false) {
 769          $this->doExpandEmptyElementTags = $truthVal;
 770  
 771          if (is_array($expandEmptyElementExceptions)) {
 772              $this->expandEmptyElementExceptions = $expandEmptyElementExceptions;
 773          }
 774      } //expandEmptyElementTags
 775  
 776      /**
 777      * Set the specified node as document element
 778      * @param Object The node that is to become document element
 779      * @return Object The new document element
 780      */
 781      function &setDocumentElement(&$node) {
 782          if ($node->nodeType == DOMIT_ELEMENT_NODE) {
 783              if ($this->documentElement == null) {
 784                  parent::appendChild($node);
 785              }
 786              else {
 787                  parent::replaceChild($node, $this->documentElement);
 788              }
 789  
 790              $this->documentElement =& $node;
 791          }
 792          else {
 793              DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
 794                  ('Cannot add a node of type ' . get_class($node) . ' as a Document Element.'));
 795          }
 796  
 797          return $node;
 798      } //setDocumentElement
 799  
 800      /**
 801      * Appends a node to the childNodes list of the current node
 802      * @param Object The node to be appended
 803      * @return Object The appended node
 804      */
 805      function &appendChild(&$node) {
 806          if ($node->nodeType == DOMIT_ELEMENT_NODE) {
 807              if ($this->documentElement == null) {
 808                  parent::appendChild($node);
 809                  $this->setDocumentElement($node);
 810              }
 811              else {
 812                  //error thrown if documentElement already exists!
 813                  DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
 814                      ('Cannot have more than one root node (documentElement) in a DOMIT_Document.'));
 815              }
 816          }
 817          else {
 818              DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
 819                  ('Cannot add a node of type ' . get_class($node) . ' to a DOMIT_Document.'));
 820          }
 821  
 822          return $node;
 823      } //appendChild
 824  
 825      /**
 826      * Replaces a node with another
 827      * @param Object The new node
 828      * @param Object The old node
 829      * @return Object The new node
 830      */
 831      function &replaceChild(&$newChild, &$oldChild) {
 832              if (($this->documentElement != null) && ($oldChild->uid == $this->documentElement->uid)) {
 833                  if ($node->nodeType == DOMIT_ELEMENT_NODE) {
 834                      //replace documentElement with new node
 835                      $this->setDocumentElement($newChild);
 836                  }
 837                  else {
 838                      DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
 839                          ('Cannot replace Document Element with a node of class ' . get_class($newChild)));
 840                  }
 841              }
 842              else {
 843                  if ($node->nodeType == DOMIT_ELEMENT_NODE) {
 844                      if ($this->documentElement != null) {
 845                          DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
 846                              ('Cannot have more than one root node (documentElement) in a DOMIT_Document.'));
 847                      }
 848                      else {
 849                          parent::replaceChild($newChild, $oldChild);
 850                      }
 851                  }
 852                  else {
 853                      DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
 854                          ('Nodes of class ' . get_class($newChild) . ' cannot be children of a DOMIT_Document.'));
 855                  }
 856              }
 857  
 858          return $newChild;
 859      } //replaceChild
 860  
 861      /**
 862      * Inserts a node to the childNodes list of the current node
 863      * @param Object The node to be inserted
 864      * @param Object The node before which the insertion is to occur
 865      * @return Object The inserted node
 866      */
 867      function &insertBefore(&$newChild, &$refChild) {
 868          $type = $newChild->nodeType;
 869  
 870          if ($type == DOMIT_ELEMENT_NODE) {
 871              if ($this->documentElement == null) {
 872                  parent::insertBefore($newChild, $refChild);
 873                  $this->setDocumentElement($newChild);
 874              }
 875              else {
 876                  //error thrown if documentElement already exists!
 877                  DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
 878                      ('Cannot have more than one root node (documentElement) in a DOMIT_Document.'));
 879              }
 880          }
 881          else {
 882              DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
 883                  ('Cannot insert a node of type ' . get_class($newChild) . ' to a DOMIT_Document.'));
 884          }
 885  
 886          return $newChild;
 887      } //insertBefore
 888  
 889      /**
 890      * Removes a node from the childNodes list of the current node
 891      * @param Object The node to be removed
 892      * @return Object The removed node
 893      */
 894      function &removeChild(&$oldChild) {
 895          if (($this->documentElement != null) && ($oldChild->uid == $this->documentElement->uid)) {
 896              parent::removeChild($oldChild);
 897              $this->documentElement = null;
 898          }
 899          else {
 900              parent::removeChild($oldChild);
 901          }
 902  
 903          $oldChild->clearReferences();
 904          return $oldChild;
 905      } //removeChild
 906  
 907      /**
 908      * Creates a new DOMIT_Lite_Element node
 909      * @param string The tag name of the element
 910      * @return Object The new element
 911      */
 912      function &createElement($tagName) {
 913          $node = new DOMIT_Lite_Element($tagName);
 914          $node->ownerDocument = $this;
 915  
 916          return $node;
 917      } //createElement
 918  
 919      /**
 920      * Creates a new DOMIT_Text node
 921      * @param string The text of the node
 922      * @return Object The new text node
 923      */
 924      function &createTextNode($data) {
 925          $node = new DOMIT_Lite_TextNode($data);
 926          $node->ownerDocument = $this;
 927  
 928          return $node;
 929      } //createTextNode
 930  
 931      /**
 932      * Creates a new DOMIT_Lite_CDATASection node
 933      * @param string The text of the CDATASection
 934      * @return Object The new CDATASection node
 935      */
 936      function &createCDATASection($data) {
 937          $node = new DOMIT_Lite_CDATASection($data);
 938          $node->ownerDocument = $this;
 939  
 940          return $node;
 941      } //createCDATASection
 942  
 943      /**
 944      * Retrieves a NodeList of child elements with the specified tag name
 945      * @param string The matching element tag name
 946      * @return Object A NodeList of found elements
 947      */
 948      function &getElementsByTagName($tagName) {
 949          $nodeList = new DOMIT_NodeList();
 950  
 951          if ($this->documentElement != null) {
 952              $this->documentElement->getNamedElements($nodeList, $tagName);
 953          }
 954  
 955          return $nodeList;
 956      } //getElementsByTagName
 957  
 958      /**
 959      * Retrieves an element or DOMIT_NodeList of elements corresponding to an Xpath-like expression.
 960      * @param string The query pattern
 961      * @param int If a single node is to be returned (rather than the entire NodeList) the index of that node
 962      * @return mixed A NodeList or single node that matches the pattern
 963      */
 964      function &getElementsByPath($pattern, $nodeIndex = 0) {
 965          require_once (DOMIT_INCLUDE_PATH . 'xml_domit_getelementsbypath.php');
 966  
 967          $gebp = new DOMIT_GetElementsByPath();
 968          $myResponse =& $gebp->parsePattern($this, $pattern, $nodeIndex);
 969  
 970          return $myResponse;
 971      } //getElementsByPath
 972  
 973      /**
 974      * Parses an xml string; first encodes string as UTF-8
 975      * @param string The xml text to be parsed
 976      * @param boolean True if SAXY is to be used instead of Expat
 977      * @param boolean False if CDATA Section are to be generated as Text nodes
 978      * @param boolean True if onLoad is to be called on each node after parsing
 979      * @return boolean True if parsing is successful
 980      */
 981  	function parseXML_utf8($xmlText, $useSAXY = true, $preserveCDATA = true, $fireLoadEvent = false) {
 982          return $this->parseXML(utf8_encode($xmlText), $useSAXY, $preserveCDATA, $fireLoadEvent);
 983      } //parseXML_utf8
 984  
 985      /**
 986      * Parses an xml string
 987      * @param string The xml text to be parsed
 988      * @param boolean True if SAXY is to be used instead of Expat
 989      * @param boolean False if CDATA Section are to be generated as Text nodes
 990      * @param boolean True if onLoad is to be called on each node after parsing
 991      * @return boolean True if parsing is successful
 992      */
 993  	function parseXML($xmlText, $useSAXY = true, $preserveCDATA = true, $fireLoadEvent = false) {
 994          require_once (DOMIT_INCLUDE_PATH . 'xml_domit_utilities.php');
 995  
 996          if ($this->doResolveErrors) {
 997              require_once (DOMIT_INCLUDE_PATH . 'xml_domit_doctor.php');
 998              $xmlText = DOMIT_Doctor::fixAmpersands($xmlText);
 999          }
1000  
1001          if (DOMIT_Utilities::validateXML($xmlText)) {
1002              $domParser = new DOMIT_Lite_Parser();
1003  
1004              if ($useSAXY || (!function_exists('xml_parser_create'))) {
1005                  //use SAXY parser to populate xml tree
1006                  $this->parser = 'SAXY_LITE';
1007                  $success = $domParser->parseSAXY($this, $xmlText, $preserveCDATA, $this->definedEntities);
1008              }
1009              else {
1010                  //use Expat parser to populate xml tree
1011                  $this->parser = 'EXPAT';
1012                  $success = $domParser->parse($this, $xmlText, $preserveCDATA);
1013              }
1014  
1015              if ($fireLoadEvent && ($this->documentElement != null)) $this->load($this->documentElement);
1016  
1017              return $success;
1018          }
1019  
1020          return false;
1021      } //parseXML
1022  
1023      /**
1024      * Parses an xml file; first encodes text as UTF-8
1025      * @param string The xml file to be parsed
1026      * @param boolean True if SAXY is to be used instead of Expat
1027      * @param boolean False if CDATA Section are to be generated as Text nodes
1028      * @param boolean True if onLoad is to be called on each node after parsing
1029      * @return boolean True if parsing is successful
1030      */
1031  	function loadXML_utf8($filename, $useSAXY = true, $preserveCDATA = true, $fireLoadEvent = false) {
1032          $xmlText = $this->getTextFromFile($filename);
1033          return $this->parseXML_utf8($xmlText, $useSAXY, $preserveCDATA, $fireLoadEvent);
1034      } //loadXML_utf8
1035  
1036      /**
1037      * Parses an xml file
1038      * @param string The xml file to be parsed
1039      * @param boolean True if SAXY is to be used instead of Expat
1040      * @param boolean False if CDATA Section are to be generated as Text nodes
1041      * @param boolean True if onLoad is to be called on each node after parsing
1042      * @return boolean True if parsing is successful
1043      */
1044  	function loadXML($filename, $useSAXY = true, $preserveCDATA = true, $fireLoadEvent = false) {
1045          $xmlText = $this->getTextFromFile($filename);
1046          return $this->parseXML($xmlText, $useSAXY, $preserveCDATA, $fireLoadEvent);
1047      } //loadXML
1048  
1049      /**
1050      * Establishes a connection, given an url
1051      * @param string The url of the data
1052      */
1053  	function establishConnection($url) {
1054          require_once (DOMIT_INCLUDE_PATH . 'php_http_client_generic.php');
1055  
1056          $host = php_http_connection::formatHost($url);
1057          $host = substr($host, 0, strpos($host, '/'));
1058  
1059          $this->setConnection($host);
1060      } //establishConnection
1061  
1062      /**
1063      * Retrieves text from a file
1064      * @param string The file path
1065      * @return string The text contained in the file
1066      */
1067  	function getTextFromFile($filename) {
1068          if ($this->doUseHTTPClient && (substr($filename, 0, 5) == 'http:')) {
1069              $this->establishConnection($filename);
1070          }
1071  
1072          if ($this->httpConnection != null) {
1073              $response =& $this->httpConnection->get($filename);
1074              $this->httpConnection->disconnect();
1075              return $response->getResponse();
1076          }
1077          else if (function_exists('file_get_contents')) {
1078              //if (file_exists($filename)) {
1079                  return file_get_contents($filename);
1080              //}
1081          }
1082          else {
1083              require_once (DOMIT_INCLUDE_PATH . 'php_file_utilities.php');
1084  
1085              $fileContents =& php_file_utilities::getDataFromFile($filename, 'r');
1086              return $fileContents;
1087          }
1088  
1089          return '';
1090      } //getTextFromFile
1091  
1092      /**
1093      * Saves the current DOM document as an xml file; first encodes text as UTF-8
1094      * @param string The path of the xml file
1095      * @param boolean True if xml text is to be normalized before saving
1096      * @return boolean True if save is successful
1097      */
1098  	function saveXML_utf8($filename, $normalized=false) {
1099          if ($normalized) {
1100              $stringRep = $this->toNormalizedString(false, true); //param 2 is $subEntities
1101          }
1102          else {
1103              $stringRep = $this->toString(false, true);
1104          }
1105  
1106          return $this->saveTextToFile($filename, utf8_encode($stringRep));
1107      } //saveXML_utf8
1108  
1109      /**
1110      * Saves the current DOM document as an xml file
1111      * @param string The path of the xml file
1112      * @param boolean True if xml text is to be normalized before saving
1113      * @return boolean True if save is successful
1114      */
1115  	function saveXML($filename, $normalized=false) {
1116          if ($normalized) {
1117              $stringRep = $this->toNormalizedString(false, true);
1118          }
1119          else {
1120              $stringRep = $this->toString(false, true);
1121          }
1122          if ($this->xmlDeclaration) {
1123              $stringRep = $this->xmlDeclaration . "\n" . $stringRep;
1124          }
1125          return $this->saveTextToFile($filename, $stringRep);
1126      } //saveXML
1127  
1128      /**
1129      * Saves text to a file
1130      * @param string The file path
1131      * @param string The text to be saved
1132      * @return boolean True if the save is successful
1133      */
1134  	function saveTextToFile($filename, $text) {
1135          if (function_exists('file_put_contents')) {
1136              file_put_contents($filename, $text);
1137          }
1138          else {
1139              require_once (DOMIT_INCLUDE_PATH . 'php_file_utilities.php');
1140              php_file_utilities::putDataToFile($filename, $text, 'w');
1141          }
1142  
1143          return (file_exists($filename) && is_writable($filename));
1144      } //saveTextToFile
1145  
1146      /**
1147      * Indicates the SAX parser used to parse the current document
1148      * @return string Either "SAXY_LITE" or "EXPAT"
1149      */
1150  	function parsedBy() {
1151          return $this->parser;
1152      } //parsedBy
1153  
1154      /**
1155      * Returns the concatented text of the current node and its children
1156      * @return string The concatented text of the current node and its children
1157      */
1158  	function getText() {
1159          if ($this->documentElement != null) {
1160              $root =& $this->documentElement;
1161              return $root->getText();
1162          }
1163  
1164          return '';
1165      } //getText
1166  
1167      /**
1168      * Returns the doctype text
1169      * @return string The doctype text, or an emty string
1170      */
1171  	function getDocType() {
1172          return $this->doctype;
1173      } //getDocType
1174  
1175      /**
1176      * Returns the xml declaration text
1177      * @return mixed The xml declaration text, or an empty string
1178      */
1179  	function getXMLDeclaration() {
1180          return $this->xmlDeclaration;
1181      } //getXMLDeclaration
1182  
1183      /**
1184      * Returns the xml declaration text
1185      * @return mixed The xml declaration text, or an empty string
1186      */
1187  	function setXMLDeclaration( $decl ) {
1188          $this->xmlDeclaration = $decl;
1189      } //setXMLDeclaration
1190  
1191      /**
1192      * Returns a reference to the DOMIT_DOMImplementation object
1193      * @return Object A reference to the DOMIT_DOMImplementation object
1194      */
1195      function &getDOMImplementation() {
1196          return $this->implementation;
1197      } //getDOMImplementation
1198  
1199      /**
1200      * Manages the firing of the onLoad() event
1201      * @param Object The parent node of the current recursion
1202      */
1203  	function load(&$contextNode) {
1204          $total = $contextNode->childCount;
1205  
1206          for ($i = 0; $i < $total; $i++) {
1207              $currNode =& $contextNode->childNodes[$i];
1208              $currNode->ownerDocument->load($currNode);
1209          }
1210  
1211          $contextNode->onLoad();
1212      } //load
1213  
1214      /**
1215      * Returns the current version of DOMIT! Lite
1216      * @return Object The current version of DOMIT! Lite
1217      */
1218  	function getVersion() {
1219          return DOMIT_LITE_VERSION;
1220      } //getVersion
1221  
1222      /**
1223      * Appends an array of entity mappings to the existing translation table
1224      *
1225      * Intended mainly to facilitate the conversion of non-ASCII entities into equivalent characters
1226      *
1227      * @param array A list of entity mappings in the format: array('&amp;' => '&');
1228      */
1229  	function appendEntityTranslationTable($table) {
1230          $this->definedEntities = $table;
1231  
1232          global $DOMIT_defined_entities_flip;
1233          $DOMIT_defined_entities_flip = array_flip($table);
1234      } //appendEntityTranslationTable
1235  
1236      /**
1237      * Generates an array representation of the node and its children
1238      * @return Array A representation of the node and its children
1239      */
1240  	function toArray() {
1241          $arReturn = array($this->nodeName => array());
1242          $total = $this->childCount;
1243  
1244          for ($i = 0; $i < $total; $i++) {
1245              $arReturn[$this->nodeName][$i] = $this->childNodes[$i]->toArray();
1246          }
1247  
1248          return $arReturn;
1249      } //toArray
1250  
1251      /**
1252      * Copies a node and/or its children
1253      * @param boolean True if all child nodes are also to be cloned
1254      * @return Object A copy of the node and/or its children
1255      */
1256      function &cloneNode($deep = false) {
1257          $className = get_class($this);
1258          $clone = new $className($this->nodeName);
1259  
1260          if ($deep) {
1261              $total = $this->childCount;
1262  
1263              for ($i = 0; $i < $total; $i++) {
1264                  $currentChild =& $this->childNodes[$i];
1265                  $clone->appendChild($currentChild->cloneNode($deep));
1266              }
1267          }
1268  
1269          return $clone;
1270      } //cloneNode
1271  
1272      /**
1273      * Generates a string representation of the node and its children
1274      * @param boolean True if HTML readable output is desired
1275      * @param boolean True if illegal xml characters in text nodes and attributes should be converted to entities
1276      * @return string The string representation
1277      */
1278  	function toString($htmlSafe = false, $subEntities = false) {
1279          $result = '';
1280          $total = $this->childCount;
1281  
1282          for ($i = 0; $i < $total; $i++) {
1283              $result .= $this->childNodes[$i]->toString(false, $subEntities);
1284          }
1285  
1286          if ($htmlSafe) $result = $this->forHTML($result);
1287  
1288          return $result;
1289      } //toString
1290  } //DOMIT_Lite_Document
1291  
1292  /**
1293  * A class representing the DOM Element
1294  *
1295  * @package domit-xmlparser
1296  * @subpackage domit-xmlparser-lite
1297  * @author John Heinstein <johnkarl@nbnet.nb.ca>
1298  */
1299  class DOMIT_Lite_Element extends DOMIT_Lite_ChildNodes_Interface {
1300      /**
1301      * DOM Element constructor
1302      * @param string The tag name of the element
1303      */
1304  	function DOMIT_Lite_Element($tagName) {
1305          $this->_constructor();
1306          $this->nodeType = DOMIT_ELEMENT_NODE;
1307          $this->nodeName = $tagName;
1308          $this->attributes = array();
1309          $this->childNodes = array();
1310      } //DOMIT_Lite_Element
1311  
1312      /**
1313      * Returns the tag name of the element
1314      * @return string The tag name of the element
1315      */
1316  	function getTagName() {
1317          return $this->nodeName;
1318      } //getTagName
1319  
1320      /**
1321      * Adds elements with the specified tag name to a NodeList collection
1322      * @param Object The NodeList collection
1323      * @param string The tag name of matching elements
1324      */
1325  	function getNamedElements(&$nodeList, $tagName) {
1326          if (($this->nodeName == $tagName) || ($tagName == '*')) {
1327              $nodeList->appendNode($this);
1328          }
1329  
1330          $total = $this->childCount;
1331  
1332          for ($i = 0; $i < $total; $i++) {
1333              $this->childNodes[$i]->getNamedElements($nodeList, $tagName);
1334          }
1335      } //getNamedElements
1336  
1337      /**
1338      * Returns the concatented text of the current node and its children
1339      * @return string The concatented text of the current node and its children
1340      */
1341  	function getText() {
1342          $text = '';
1343          $numChildren = $this->childCount;
1344  
1345          for ($i = 0; $i < $numChildren; $i++) {
1346              $child =& $this->childNodes[$i];
1347              $text .= $child->getText();
1348          }
1349  
1350          return $text;
1351      } //getText
1352  
1353      /**
1354      * If a child text node exists, sets the nodeValue to $data. A child text node is created if none exists
1355      * @param string The text data of the node
1356      */
1357  	function setText($data) {
1358          switch ($this->childCount) {
1359              case 1:
1360                  if ($this->firstChild->nodeType == DOMIT_TEXT_NODE) {
1361                      $this->firstChild->setText($data);
1362                  }
1363                  break;
1364  
1365              case 0:
1366                  $childTextNode =& $this->ownerDocument->createTextNode($data);
1367                  $this->appendChild($childTextNode);
1368                  break;
1369  
1370              default:
1371                  //do nothing. Maybe throw error???
1372          }
1373      } //setText
1374  
1375      /**
1376      * Retrieves a NodeList of child elements with the specified tag name
1377      * @param string The matching element tag name
1378      * @return Object A NodeList of found elements
1379      */
1380      function &getElementsByTagName($tagName) {
1381          $nodeList = new DOMIT_NodeList();
1382          $this->getNamedElements($nodeList, $tagName);
1383  
1384          return $nodeList;
1385      } //getElementsByTagName
1386  
1387      /**
1388      * Retrieves an element or DOMIT_NodeList of elements corresponding to an Xpath-like expression.
1389      * @param string The query pattern
1390      * @param int If a single node is to be returned (rather than the entire NodeList) the index of that node
1391      * @return mixed A NodeList or single node that matches the pattern
1392      */
1393      function &getElementsByPath($pattern, $nodeIndex = 0) {
1394          require_once (DOMIT_INCLUDE_PATH . 'xml_domit_getelementsbypath.php');
1395  
1396          $gebp = new DOMIT_GetElementsByPath();
1397          $myResponse = $gebp->parsePattern($this, $pattern, $nodeIndex);
1398  
1399          return $myResponse;
1400      } //getElementsByPath
1401  
1402      /**
1403      * Gets the value of the specified attribute, if it exists
1404      * @param string The attribute name
1405      * @return string The attribute value
1406      */
1407  	function getAttribute($name) {
1408          if ($this->hasAttribute($name)) {
1409              return $this->attributes[$name];
1410          }
1411          else {
1412              /*
1413              DOMIT_DOMException::raiseException(DOMIT_NOT_FOUND_ERR,
1414              ('No attribute named ' . $name . 'exists.'));
1415              */
1416              // Joomla! hack
1417              return null;
1418          }
1419      } //getAttribute
1420  
1421      /**
1422      * Sets the value of the specified attribute; creates a new attribute if one doesn't exist
1423      * @param string The attribute name
1424      * @param string The desired attribute value
1425      */
1426  	function setAttribute($name, $value) {
1427          $this->attributes[$name] = $value;
1428      } //setAttribute
1429  
1430      /**
1431      * Removes the specified attribute
1432      * @param string The name of the attribute to be removed
1433      */
1434  	function removeAttribute($name) {
1435          if ($this->hasAttribute($name)) {
1436              unset($this->attributes[$name]);
1437          }
1438      } //removeAttribute
1439  
1440      /**
1441      * Determines whether an attribute with the specified name exists
1442      * @param string The name of the attribute
1443      * @return boolean True if the attribute exists
1444      */
1445  	function hasAttribute($name) {
1446          return isset($this->attributes[$name]);
1447      } //hasAttribute
1448  
1449      /**
1450      * Collapses adjacent text nodes in entire element subtree
1451      */
1452  	function normalize() {
1453          if ($this->hasChildNodes()) {
1454              $currNode =& $this->childNodes[0];
1455  
1456              while ($currNode->nextSibling != null) {
1457                  $nextNode =& $currNode->nextSibling;
1458  
1459                  if (($currNode->nodeType == DOMIT_TEXT_NODE) &&
1460                      ($nextNode->nodeType == DOMIT_TEXT_NODE)) {
1461                      $currNode->nodeValue .= $nextNode->nodeValue;
1462                      $this->removeChild($nextNode);
1463                  }
1464                  else {
1465                      $currNode->normalize();
1466                  }
1467  
1468                  if ($currNode->nextSibling != null) {
1469                      $currNode =& $currNode->nextSibling;
1470                  }
1471              }
1472          }
1473      } //normalize
1474  
1475      /**
1476      * Generates an array representation of the node and its children
1477      * @return Array A representation of the node and its children
1478      */
1479  	function toArray() {
1480          $arReturn = array($this->nodeName => array("attributes" => $this->attributes));
1481          $total = $this->childCount;
1482  
1483          for ($i = 0; $i < $total; $i++) {
1484              $arReturn[$this->nodeName][$i] = $this->childNodes[$i]->toArray();
1485          }
1486  
1487          return $arReturn;
1488      } //toArray
1489  
1490      /**
1491      * Copies a node and/or its children
1492      * @param boolean True if all child nodes are also to be cloned
1493      * @return Object A copy of the node and/or its children
1494      */
1495      function &cloneNode($deep = false) {
1496          $className = get_class($this);
1497          $clone = new $className($this->nodeName);
1498  
1499          $clone->attributes = $this->attributes;
1500  
1501          if ($deep) {
1502              $total = $this->childCount;
1503  
1504              for ($i = 0; $i < $total; $i++) {
1505                  $currentChild =& $this->childNodes[$i];
1506                  $clone->appendChild($currentChild->cloneNode($deep));
1507              }
1508          }
1509  
1510          return $clone;
1511      } //cloneNode
1512  
1513      /**
1514      * Generates a string representation of the node and its children
1515      * @param boolean True if HTML readable output is desired
1516      * @param boolean True if illegal xml characters in text nodes and attributes should be converted to entities
1517      * @return string The string representation
1518      */
1519  	function toString($htmlSafe = false, $subEntities = false) {
1520          require_once (DOMIT_INCLUDE_PATH . 'xml_domit_utilities.php');
1521          global $DOMIT_defined_entities_flip;
1522  
1523          $result = '<' . $this->nodeName;
1524  
1525          //get attributes
1526          foreach ($this->attributes as $key => $value) {
1527              $result .= ' ' . $key . '="';
1528              $result .= $subEntities ? DOMIT_Utilities::convertEntities($value,
1529                              $DOMIT_defined_entities_flip) : $value;
1530              $result .= '"';
1531          }
1532  
1533          //get children
1534          $myNodes =& $this->childNodes;
1535          $total = count($myNodes);
1536  
1537          if ($total != 0) {
1538              $result .= '>';
1539  
1540              for ($i = 0; $i < $total; $i++) {
1541                  $child =& $myNodes[$i];
1542                  $result .= $child->toString(false, $subEntities);
1543              }
1544  
1545              $result .= '</' . $this->nodeName . '>';
1546          }
1547          else {
1548              if ($this->ownerDocument->doExpandEmptyElementTags) {
1549                  if (in_array($this->nodeName, $this->ownerDocument->expandEmptyElementExceptions)) {
1550                      $result .= ' />';
1551                  }
1552                  else {
1553                      $result .= '></' . $this->nodeName . '>';
1554                  }
1555              }
1556              else {
1557                  if (in_array($this->nodeName, $this->ownerDocument->expandEmptyElementExceptions)) {
1558                      $result .= '></' . $this->nodeName . '>';
1559                  }
1560                  else {
1561                      $result .= ' />';
1562                  }
1563              }
1564          }
1565  
1566          if ($htmlSafe) $result = $this->forHTML($result);
1567  
1568          return $result;
1569      } //toString
1570  } //DOMIT_Lite_Element
1571  
1572  /**
1573  * A class representing the DOM Text Node
1574  *
1575  * @package domit-xmlparser
1576  * @subpackage domit-xmlparser-lite
1577  * @author John Heinstein <johnkarl@nbnet.nb.ca>
1578  */
1579  class DOMIT_Lite_TextNode extends DOMIT_Lite_Node {
1580      /**
1581      * DOM Text Node constructor
1582      * @param string The text of the node
1583      */
1584  	function DOMIT_Lite_TextNode($data) {
1585          $this->_constructor();
1586          $this->nodeType = DOMIT_TEXT_NODE;
1587          $this->nodeName = '#text';
1588          $this->setText($data);
1589      } //DOMIT_Lite_TextNode
1590  
1591      /**
1592      * Returns the text contained in the current node
1593      * @return string The text of the current node
1594      */
1595  	function getText() {
1596          return $this->nodeValue;
1597      } //getText
1598  
1599       /**
1600      * Sets the text contained in the current node to $data.
1601      * @param string The text data of the node
1602      */
1603  	function setText($data) {
1604          $this->nodeValue = $data;
1605      } //setText
1606  
1607      /**
1608      * Generates an array representation of the node and its children
1609      * @return Array A representation of the node and its children
1610      */
1611  	function toArray() {
1612          return $this->toString();
1613      } //toArray
1614  
1615      /**
1616      * Copies a node and/or its children
1617      * @param boolean True if all child nodes are also to be cloned
1618      * @return Object A copy of the node and/or its children
1619      */
1620      function &cloneNode($deep = false) {
1621          $className = get_class($this);
1622          $clone = new $className($this->nodeValue);
1623  
1624          return $clone;
1625      } //cloneNode
1626  
1627      /**
1628      * Generates a string representation of the node and its children
1629      * @param boolean True if HTML readable output is desired
1630      * @param boolean True if illegal xml characters should be converted to entities
1631      * @return string The string representation
1632      */
1633  	function toString($htmlSafe = false, $subEntities = false) {
1634          require_once (DOMIT_INCLUDE_PATH . 'xml_domit_utilities.php');
1635          global $DOMIT_defined_entities_flip;
1636  
1637          $result = $subEntities ? DOMIT_Utilities::convertEntities($this->nodeValue,
1638                          $DOMIT_defined_entities_flip) : $this->nodeValue;
1639  
1640          if ($htmlSafe) $result = $this->forHTML($result);
1641  
1642          return $result;
1643      } //toString
1644  } //DOMIT_Lite_TextNode
1645  
1646  /**
1647  * A class representing the DOM CDATA Section
1648  *
1649  * @package domit-xmlparser
1650  * @subpackage domit-xmlparser-lite
1651  * @author John Heinstein <johnkarl@nbnet.nb.ca>
1652  */
1653  class DOMIT_Lite_CDATASection extends DOMIT_Lite_TextNode {
1654      /**
1655      * DOM CDATA Section node constructor
1656      * @param string The text of the node
1657      */
1658  	function DOMIT_Lite_CDATASection($data) {
1659          $this->_constructor();
1660          $this->nodeType = DOMIT_CDATA_SECTION_NODE;
1661          $this->nodeName = '#cdata-section';
1662          $this->setText($data);
1663      } //DOMIT_Lite_CDATASection
1664  
1665      /**
1666      * Generates a string representation of the node and its children
1667      * @param boolean True if HTML readable output is desired
1668      * @param boolean True if illegal xml characters should be converted to entities
1669      * @return string The string representation
1670      */
1671  	function toString($htmlSafe = false, $subEntities = false) {
1672          $result = '<![CDATA[';
1673          $result .= $subEntities ? str_replace("]]>", "]]&gt;", $this->nodeValue) :
1674                                   $this->nodeValue;
1675          $result .= ']]>';
1676  
1677          if ($htmlSafe) $result = $this->forHTML($result);
1678  
1679          return $result;
1680      } //toString
1681  } //DOMIT_Lite_CDATASection
1682  
1683  /**
1684  * Manages the generation of a DOMIT! document from SAX events
1685  *
1686  * @package domit-xmlparser
1687  * @subpackage domit-xmlparser-lite
1688  * @author John Heinstein <johnkarl@nbnet.nb.ca>
1689  */
1690  class DOMIT_Lite_Parser {
1691      /** @var Object A reference to the resulting xmldoc */
1692      var $xmlDoc = null;
1693      /** @var Object A reference to the current node in the parsing process */
1694      var $currentNode = null;
1695      /** @var Object A reference to the last child in the parsing process */
1696      var $lastChild = null;
1697      /** @var boolean True if currently parsing a CDATA Section */
1698      var $inCDATASection = false; //flag for Expat
1699      /** @var boolean True if currently parsing a Text node */
1700      var $inTextNode = false;
1701      /** @var boolean True is CDATA Section nodes are not to be converted into Text nodes */
1702      var $preserveCDATA;
1703      /** @var string A container for holding the currently parsed text data */
1704      var $parseContainer = '';
1705      /** @var string The current docutype text */
1706      var $parseItem = '';
1707  
1708      /**
1709      * Parses xml text using Expat
1710      * @param Object A reference to the DOM document that the xml is to be parsed into
1711      * @param string The text to be parsed
1712      * @param boolean True if CDATA Section nodes are not to be converted into Text nodes
1713      * @return boolean True if the parsing is successful
1714      */
1715  	function parse (&$myXMLDoc, $xmlText, $preserveCDATA = true) {
1716          $this->xmlDoc =& $myXMLDoc;
1717          $this->lastChild =& $this->xmlDoc;
1718  
1719          $this->preserveCDATA = $preserveCDATA;
1720  
1721          /*
1722          //create instance of expat parser (should be included in php distro)
1723          if (version_compare(phpversion(), '5.0', '<=')) {
1724              $parser = xml_parser_create('');
1725          } else {
1726              // special handling for encoding support
1727              if (defined( '_ISO' )) {
1728                  $iso = explode( '=', _ISO );
1729                  $parser = xml_parser_create($iso[1]);
1730              } else {
1731                  $parser = xml_parser_create();
1732              }
1733          }
1734          */
1735          
1736          //create instance of expat parser (should be included in php distro)
1737          if (version_compare(phpversion(), '5.0', '<=')) {
1738              $parser = xml_parser_create('');
1739          } else {
1740              $parser = xml_parser_create('iso-8859-1');
1741          }
1742  
1743          //set handlers for SAX events
1744          xml_set_object($parser, $this);
1745          xml_set_element_handler($parser, 'startElement', 'endElement');
1746          xml_set_character_data_handler($parser, 'dataElement');
1747          xml_set_default_handler($parser, 'defaultDataElement');
1748          xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
1749  
1750          if (!$this->xmlDoc->preserveWhitespace) {
1751              xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
1752          }
1753          else {
1754              xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
1755          }
1756  
1757          //parse out whitespace -  (XML_OPTION_SKIP_WHITE = 1 does not
1758          //seem to work consistently across versions of PHP and Expat
1759          if (!$this->xmlDoc->preserveWhitespace) {
1760              $xmlText = eregi_replace('>' . "[[:space:]]+" . '<' , '><', $xmlText);
1761          }
1762  
1763          $success = xml_parse($parser, $xmlText);
1764  
1765          $this->xmlDoc->errorCode = xml_get_error_code($parser);
1766          $this->xmlDoc->errorString = xml_error_string($this->xmlDoc->errorCode);
1767  
1768          xml_parser_free($parser);
1769  
1770          return $success;
1771      } //parse
1772  
1773      /**
1774      * Parses xml text using SAXY
1775      * @param Object A reference to the DOM document that the xml is to be parsed into
1776      * @param string The text to be parsed
1777      * @param boolean True if CDATA Section nodes are not to be converted into Text nodes
1778      * @return boolean True if the parsing is successful
1779      */
1780  	function parseSAXY(&$myXMLDoc, $xmlText, $preserveCDATA, $definedEntities) {
1781          require_once (DOMIT_INCLUDE_PATH . 'xml_saxy_lite_parser.php');
1782  
1783          $this->xmlDoc =& $myXMLDoc;
1784          $this->lastChild =& $this->xmlDoc;
1785  
1786          //create instance of SAXY parser
1787          $parser = new SAXY_Lite_Parser();
1788          $parser->appendEntityTranslationTable($definedEntities);
1789  
1790          //not yet implemented in SAXY!!!
1791          $parser->preserveWhitespace = $this->xmlDoc->preserveWhitespace;
1792  
1793          $parser->xml_set_element_handler(array(&$this, 'startElement'), array(&$this, 'endElement'));
1794          $parser->xml_set_character_data_handler(array(&$this, 'dataElement'));
1795  
1796          if ($preserveCDATA) {
1797              $parser->xml_set_cdata_section_handler(array(&$this, 'cdataElement'));
1798          }
1799  
1800          $success = $parser->parse($xmlText);
1801  
1802          $this->xmlDoc->errorCode = $parser->xml_get_error_code();
1803          $this->xmlDoc->errorString = $parser->xml_error_string($this->xmlDoc->errorCode);
1804  
1805          return $success;
1806      } //parseSAXY
1807  
1808      /**
1809      * Generates and appends a new text node from the parseContainer text
1810      */
1811  	function dumpTextNode() {
1812          //traps for mixed content
1813          $currentNode =& $this->xmlDoc->createTextNode($this->parseContainer);
1814          $this->lastChild->appendChild($currentNode);
1815          $this->inTextNode = false;
1816          $this->parseContainer = '';
1817      } //dumpTextNode
1818  
1819      /**
1820      * Catches a start element event and processes the data
1821      * @param Object A reference to the current SAX parser
1822      * @param string The tag name of the current element
1823      * @param Array An array of the element attributes
1824      */
1825  	function startElement(&$parser, $name, $attrs) {
1826          if ($this->inTextNode) {
1827              $this->dumpTextNode();
1828          }
1829  
1830          $currentNode =& $this->xmlDoc->createElement($name);
1831          $currentNode->attributes = $attrs;
1832          $this->lastChild->appendChild($currentNode);
1833          $this->lastChild =& $currentNode;
1834      } //startElement
1835  
1836      /**
1837      * Catches an end element event and processes the data
1838      * @param Object A reference to the current SAX parser
1839      * @param string The tag name of the current element
1840      */
1841  	function endElement(&$parser, $name) {
1842          if ($this->inTextNode) {
1843              $this->dumpTextNode();
1844          }
1845  
1846          $this->lastChild =& $this->lastChild->parentNode;
1847      } //endElement
1848  
1849      /**
1850      * Catches a data 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 dataElement(&$parser, $data) {
1855          if (!$this->inCDATASection) $this->inTextNode = true;
1856  
1857          $this->parseContainer .= $data;
1858      } //dataElement
1859  
1860      /**
1861      * Catches a CDATA Section event and processes the text
1862      * @param Object A reference to the current SAX parser
1863      * @param string The current text data
1864      */
1865  	function cdataElement(&$parser, $data) {
1866          $currentNode =& $this->xmlDoc->createCDATASection($data);
1867  
1868          $this->lastChild->appendChild($currentNode);
1869      } //cdataElement
1870  
1871      /**
1872      * Catches a default data event and processes the data
1873      * @param Object A reference to the current SAX parser
1874      * @param string The current data
1875      */
1876  	function defaultDataElement(&$parser, $data) {
1877          if (strlen($data) > 2){
1878              $pre = strtoupper(substr($data, 0, 3));
1879  
1880              switch ($pre) {
1881                  case '<![': //cdata section coming
1882                      if ($this->preserveCDATA) {
1883                          $this->inCDATASection = true;
1884                      }
1885                      break;
1886                  case ']]>': //cdata remnant - ignore
1887                      if ($this->preserveCDATA) {
1888                          $currentNode =& $this->xmlDoc->createCDATASection($this->parseContainer);
1889                          $this->lastChild->appendChild($currentNode);
1890                          $this->inCDATASection = false;
1891                          $this->parseContainer = '';
1892                      }
1893                      else {
1894                          $this->dumpTextNode();
1895                      }
1896  
1897                      break;
1898              }
1899          }
1900      } //defaultDataElement
1901  } //DOMIT_Lite_Parser
1902  
1903  ?>


Généré le : Wed Nov 21 14:43:32 2007 par Balluche grâce à PHPXref 0.7
  Clicky Web Analytics