[ Index ]
 

Code source de Joomla 1.0.13

Accédez au Source d'autres logiciels libres

title

Body

[fermer]

/includes/domit/ -> xml_domit_parser.php (source)

   1  <?php
   2  /**
   3  * DOMIT! is a non-validating, but lightweight and fast DOM parser for PHP
   4  * @package domit-xmlparser
   5  * @subpackage domit-xmlparser-main
   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! */
  19  define ('DOMIT_VERSION', '1.01');
  20  
  21  /** XML namespace URI */
  22  define ('DOMIT_XML_NAMESPACE', 'http://www.w3.org/xml/1998/namespace');
  23  
  24  /** XMLNS namespace URI */
  25  define ('DOMIT_XMLNS_NAMESPACE', 'http://www.w3.org/2000/xmlns/');
  26  
  27  /**
  28  * @global array Flipped version of $definedEntities array, to allow two-way conversion of entities
  29  *
  30  * Made global so that Attr nodes, which have no ownerDocument property, can access the array
  31  */
  32  $GLOBALS['DOMIT_defined_entities_flip'] = array();
  33  
  34  require_once (DOMIT_INCLUDE_PATH . 'xml_domit_shared.php');
  35  
  36  /**
  37  * The base class of all DOMIT node types
  38  *
  39  * @package domit-xmlparser
  40  * @subpackage domit-xmlparser-main
  41  * @author John Heinstein <johnkarl@nbnet.nb.ca>
  42  */
  43  class DOMIT_Node {
  44      /** @var string The name of the node, varies according to node type */
  45      var $nodeName = null;
  46      /** @var string The value of the node, varies according to node type */
  47      var $nodeValue = null;
  48      /** @var int The type of node, e.g. CDataSection */
  49      var $nodeType = null;
  50      /** @var Object A reference to the parent of the current node */
  51      var $parentNode = null;
  52      /** @var Array An array of child node references */
  53      var $childNodes = null;
  54      /** @var Object A reference to the first node in the childNodes list */
  55      var $firstChild = null;
  56      /** @var Object A reference to the last node in the childNodes list */
  57      var $lastChild = null;
  58      /** @var Object A reference to the node prior to the current node in its parents childNodes list */
  59      var $previousSibling = null;
  60      /** @var Object A reference to the node after the current node in its parents childNodes list */
  61      var $nextSibling = null;
  62      /** @var Object A NodeList of attribute nodes */
  63      var $attributes = null;
  64      /** @var Object A reference to the Document node */
  65      var $ownerDocument = null;
  66      /** @var String A URI that identifies the XML namespace to which the node belongs */
  67      var $namespaceURI = null;
  68      /** @var String The namespace prefix for the node */
  69      var $prefix = null;
  70      /** @var String The local name of the node */
  71      var $localName = null;
  72      /** @var string The unique node id */
  73      var $uid;
  74      /** @var int The number of children of the current node */
  75      var $childCount = 0;
  76  
  77      /**
  78      * Raises error if abstract class is directly instantiated
  79      */
  80  	function DOMIT_Node() {
  81          DOMIT_DOMException::raiseException(DOMIT_ABSTRACT_CLASS_INSTANTIATION_ERR,
  82               'Cannot instantiate abstract class DOMIT_Node');
  83      } //DOMIT_Node
  84  
  85      /**
  86      * DOMIT_Node constructor, assigns a uid
  87      */
  88  	function _constructor() {
  89          global $uidFactory;
  90          $this->uid = $uidFactory->generateUID();
  91      } //_constructor
  92  
  93      /**
  94      * Appends a node to the childNodes list of the current node
  95      * @abstract
  96      * @param Object The node to be appended
  97      * @return Object The appended node
  98      */
  99      function &appendChild(&$child) {
 100          DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
 101              ('Method appendChild cannot be called by class ' . get_class($this)));
 102      } //appendChild
 103  
 104      /**
 105      * Inserts a node to the childNodes list of the current node
 106      * @abstract
 107      * @param Object The node to be inserted
 108      * @param Object The node before which the insertion is to occur
 109      * @return Object The inserted node
 110      */
 111      function &insertBefore(&$newChild, &$refChild) {
 112          DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
 113              ('Method insertBefore cannot be called by class ' . get_class($this)));
 114      } //insertBefore
 115  
 116      /**
 117      * Replaces a node with another
 118      * @abstract
 119      * @param Object The new node
 120      * @param Object The old node
 121      * @return Object The new node
 122      */
 123      function &replaceChild(&$newChild, &$oldChild) {
 124          DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
 125              ('Method replaceChild cannot be called by class ' . get_class($this)));
 126      } //replaceChild
 127  
 128      /**
 129      * Removes a node from the childNodes list of the current node
 130      * @abstract
 131      * @param Object The node to be removed
 132      * @return Object The removed node
 133      */
 134      function &removeChild(&$oldChild) {
 135          DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
 136              ('Method removeChild cannot be called by class ' . get_class($this)));
 137      } //removeChild
 138  
 139      /**
 140      * Returns the index of the specified node in a childNodes list
 141      * @param Array The childNodes array to be searched
 142      * @param Object The node targeted by the search
 143      * @return int The index of the target node, or -1 if not found
 144      */
 145  	function getChildNodeIndex(&$arr, &$child) {
 146          $index = -1;
 147          $total = count($arr);
 148  
 149          for ($i = 0; $i < $total; $i++) {
 150              if ($child->uid == $arr[$i]->uid) {
 151                  $index = $i;
 152                  break;
 153              }
 154          }
 155  
 156          return $index;
 157      } //getChildNodeIndex
 158  
 159      /**
 160      * Determines whether a node has any children
 161      * @return boolean True if any child nodes are present
 162      */
 163  	function hasChildNodes() {
 164          return ($this->childCount > 0);
 165      } //hasChildNodes
 166  
 167      /**
 168      * Determines whether a node has any attributes
 169      * @return boolean True if the node has attributes
 170      */
 171  	function hasAttributes() {
 172          //overridden in DOMIT_Element
 173          return false;
 174      } //hasChildNodes
 175  
 176      /**
 177      * Collapses adjacent text nodes in entire node subtree
 178      */
 179  	function normalize() {
 180          if (($this->nodeType == DOMIT_DOCUMENT_NODE) && ($this->documentElement != null)) {
 181              $this->documentElement->normalize();
 182          }
 183      } //normalize
 184  
 185      /**
 186      * Copies a node and/or its children
 187      * @abstract
 188      * @param boolean True if all child nodes are also to be cloned
 189      * @return Object A copy of the node and/or its children
 190      */
 191      function &cloneNode($deep = false) {
 192          DOMIT_DOMException::raiseException(DOMIT_ABSTRACT_METHOD_INVOCATION_ERR,
 193               'Cannot invoke abstract method DOMIT_Node->cloneNode($deep). Must provide an overridden method in your subclass.');
 194      } //cloneNode
 195  
 196      /**
 197      * Adds elements with the specified tag name to a NodeList collection
 198      * @param Object The NodeList collection
 199      * @param string The tag name of matching elements
 200      */
 201  	function getNamedElements(&$nodeList, $tagName) {
 202          //Implemented in DOMIT_Element.
 203          //Needs to be here though! This is called against all nodes in the document.
 204      } //getNamedElements
 205  
 206      /**
 207      * Sets the ownerDocument property of a node to the containing DOMIT_Document
 208      * @param Object A reference to the document element of the DOMIT_Document
 209      */
 210  	function setOwnerDocument(&$rootNode) {
 211          if ($rootNode->ownerDocument == null) {
 212              unset($this->ownerDocument);
 213              $this->ownerDocument = null;
 214          }
 215          else {
 216              $this->ownerDocument =& $rootNode->ownerDocument;
 217          }
 218  
 219          $total = $this->childCount;
 220  
 221          for ($i = 0; $i < $total; $i++) {
 222              $this->childNodes[$i]->setOwnerDocument($rootNode);
 223          }
 224      } //setOwnerDocument
 225  
 226      /**
 227      * Tests whether a value is null, and if so, returns a default value
 228      * @param mixed The value to be tested
 229      * @param mixed The default value
 230      * @return mixed The specified value, or the default value if null
 231      */
 232      function &nvl(&$value,$default) {
 233            if (is_null($value)) return $default;
 234            return $value;
 235      } //nvl
 236  
 237      /**
 238      * Retrieves an element or DOMIT_NodeList of elements corresponding to an Xpath-like expression.
 239      * @abstract
 240      * @param string The query pattern
 241      * @param int If a single node is to be returned (rather than the entire NodeList) the index of that node
 242      * @return mixed A NodeList or single node that matches the pattern
 243      */
 244      function &getElementsByPath($pattern, $nodeIndex = 0) {
 245           DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
 246              ('Method getElementsByPath cannot be called by class ' . get_class($this)));
 247      } //getElementsByPath
 248  
 249      /**
 250      * Retrieves an element or DOMIT_NodeList of elements corresponding to an Xpath-like attribute expression (NOT YET IMPLEMENTED!)
 251      * @abstract
 252      * @param string The query pattern
 253      * @param int If a single node is to be returned (rather than the entire NodeList) the index of that node
 254      * @return mixed A NodeList or single node that matches the pattern
 255      */
 256      function &getElementsByAttributePath($pattern, $nodeIndex = 0) {
 257           DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
 258              ('Method getElementsByAttributePath cannot be called by class ' . get_class($this)));
 259      } //getElementsByAttributePath
 260  
 261      /**
 262      * Adds all child nodes of the specified nodeType to the NodeList
 263      * @abstract
 264      * @param Object The NodeList collection
 265      * @param string The nodeType of matching nodes
 266      */
 267  	function getTypedNodes(&$nodeList, $type) {
 268          DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
 269              ('Method getTypedNodes cannot be called by class ' . get_class($this)));
 270      } //getTypedNodes
 271  
 272      /**
 273      * Adds all child nodes of the specified nodeValue to the NodeList
 274      * @abstract
 275      * @param Object The NodeList collection
 276      * @param string The nodeValue of matching nodes
 277      */
 278  	function getValuedNodes(&$nodeList, $value) {
 279          DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
 280              ('Method getValuedNodes cannot be called by class ' . get_class($this)));
 281      } //getValuedNodes
 282  
 283      /**
 284      * Returns the concatented text of the current node and its children
 285      * @return string The concatented text of the current node and its children
 286      */
 287  	function getText() {
 288          return $this->nodeValue;
 289      } //getText
 290  
 291      /**
 292      * Indicates whether the specified feature is supported by the DOM implementation and this node
 293      * @param string The feature
 294      * @param string The version of the DOM implementation
 295      * @return boolean True if the specified feature is supported
 296      */
 297  	function isSupported($feature, $version = null) {
 298          //don't worry about parsing based on version at this point in time;
 299          //the only feature that is supported is 'XML'...
 300          if (($version == '1.0') || ($version == '2.0') || ($version == null)) {
 301              if (strtoupper($feature) == 'XML') {
 302                  return true;
 303              }
 304          }
 305  
 306          return false;
 307      } //isSupported
 308  
 309      /**
 310      * Formats a string for presentation as HTML
 311      * @param string The string to be formatted
 312      * @param boolean True if the string is to be sent directly to output
 313      * @return string The HTML formatted string
 314      */
 315  	function forHTML($str, $doPrint = false) {
 316          require_once (DOMIT_INCLUDE_PATH . 'xml_domit_utilities.php');
 317          return DOMIT_Utilities::forHTML($str, $doPrint);
 318      } //forHTML
 319  
 320      /**
 321      * Generates an array representation of the node and its children
 322      * @abstract
 323      * @return Array A representation of the node and its children
 324      */
 325  	function toArray() {
 326          DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
 327              ('Method toArray cannot be called by class ' . get_class($this)));
 328      } //toArray
 329  
 330      /**
 331      * A node event that can be set to fire upon document loading, used for node initialization
 332      * @abstract
 333      */
 334  	function onLoad() {
 335          //you can override this method if you subclass any of the
 336          //DOMIT_Nodes. It's a way of performing
 337          //initialization of your subclass as soon as the document
 338          //has been loaded (as opposed to as soon as the current node
 339          //has been instantiated).
 340      } //onLoad
 341  
 342      /**
 343      * Clears previousSibling, nextSibling, and parentNode references from a node that has been removed
 344      */
 345  	function clearReferences() {
 346          if ($this->previousSibling != null) {
 347              unset($this->previousSibling);
 348              $this->previousSibling = null;
 349          }
 350          if ($this->nextSibling != null) {
 351              unset($this->nextSibling);
 352              $this->nextSibling = null;
 353          }
 354          if ($this->parentNode != null) {
 355              unset($this->parentNode);
 356              $this->parentNode = null;
 357          }
 358      } //clearReferences
 359  
 360      /**
 361      * Removes the node from the document
 362      */
 363  	function delete () {
 364          if ($this->parentNode != null) {
 365              $this->parentNode->removeChild($node);
 366          }
 367      } //delete
 368  
 369      /**
 370      * Generates a normalized (formatted for readability) representation of the node and its children
 371      * @param boolean True if HTML readable output is desired
 372      * @param boolean True if illegal xml characters in text nodes and attributes should be converted to entities
 373      * @return string The formatted string representation
 374      */
 375  	function toNormalizedString($htmlSafe = false, $subEntities = false) {
 376          //require this file for generating a normalized (readable) xml string representation
 377          require_once (DOMIT_INCLUDE_PATH . 'xml_domit_utilities.php');
 378          global $DOMIT_defined_entities_flip;
 379  
 380          $result = DOMIT_Utilities::toNormalizedString($this, $subEntities, $DOMIT_defined_entities_flip);
 381  
 382          if ($htmlSafe) $result = $this->forHTML($result);
 383  
 384          return $result;
 385      } //toNormalizedString
 386  } //DOMIT_Node
 387  
 388  /**
 389  * A parent class for nodes which possess child nodes
 390  *
 391  * @package domit-xmlparser
 392  * @subpackage domit-xmlparser-main
 393  * @author John Heinstein <johnkarl@nbnet.nb.ca>
 394  */
 395  class DOMIT_ChildNodes_Interface extends DOMIT_Node {
 396      /**
 397      * Raises error if abstract class is directly instantiated
 398      */
 399  	function DOMIT_ChildNodes_Interface() {
 400          DOMIT_DOMException::raiseException(DOMIT_ABSTRACT_CLASS_INSTANTIATION_ERR,
 401               'Cannot instantiate abstract class DOMIT_ChildNodes_Interface');
 402      } //DOMIT_ChildNodes_Interface
 403  
 404      /**
 405      * Appends a node to the childNodes list of the current node
 406      * @param Object The node to be appended
 407      * @return Object The appended node
 408      */
 409      function &appendChild(&$child) {
 410          if ($child->nodeType == DOMIT_ATTRIBUTE_NODE) {
 411              DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
 412                  ('Cannot add a node of type ' . get_class($child) . ' using appendChild'));
 413          }
 414          else if ($child->nodeType == DOMIT_DOCUMENT_FRAGMENT_NODE) {
 415              $total = $child->childCount;
 416  
 417              for ($i = 0; $i < $total; $i++) {
 418                  $currChild =& $child->childNodes[$i];
 419                  $this->appendChild($currChild);
 420              }
 421          }
 422          else {
 423              if (!($this->hasChildNodes())) {
 424                  $this->childNodes[0] =& $child;
 425                  $this->firstChild =& $child;
 426              }
 427              else {
 428                  //remove $child if it already exists
 429                  $index = $this->getChildNodeIndex($this->childNodes, $child);
 430      
 431                  if ($index != -1) {
 432                      $this->removeChild($child);
 433                  }
 434  
 435                  //append child
 436                  $numNodes = $this->childCount;
 437                  //BB: was bug auto-created wrong childnodes[-1]: added IF
 438                  if ($numNodes > 0) {
 439                      $prevSibling =& $this->childNodes[($numNodes - 1)];
 440                  }
 441      
 442                  $this->childNodes[$numNodes] =& $child;
 443      
 444                  //set next and previous relationships
 445                  //BB: added this line and the else part to finish correcting bug
 446                  if (isset( $prevSibling )) {
 447                      $child->previousSibling =& $prevSibling;
 448                      $prevSibling->nextSibling =& $child;
 449                  } else {
 450                      unset( $child->previousSibling );
 451                      $child->previousSibling = null;
 452                      $this->firstChild =& $child;
 453                  }
 454              }
 455          }
 456  
 457          $this->lastChild =& $child;
 458          $child->parentNode =& $this;
 459  
 460          unset($child->nextSibling);
 461          $child->nextSibling = null;
 462  
 463          $child->setOwnerDocument($this);
 464          $this->childCount++;
 465  
 466          return $child;
 467  
 468      } //appendChild
 469  
 470      /**
 471      * Inserts a node to the childNodes list of the current node
 472      * @param Object The node to be inserted
 473      * @param Object The node before which the insertion is to occur
 474      * @return Object The inserted node
 475      */
 476      function &insertBefore(&$newChild, &$refChild) {
 477          if ($newChild->nodeType == DOMIT_ATTRIBUTE_NODE) {
 478              DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
 479                  ('Cannot add a node of type ' . get_class($newChild) . ' using insertBefore'));
 480          }
 481  
 482          if (($refChild->nodeType == DOMIT_DOCUMENT_NODE) ||
 483              //($refChild->parentNode->nodeType == DOMIT_DOCUMENT_NODE) ||
 484              ($refChild->parentNode == null)) {
 485  
 486              DOMIT_DOMException::raiseException(DOMIT_NOT_FOUND_ERR,
 487                   'Reference child not present in the child nodes list.');
 488          }
 489  
 490          //if reference child is also the node to be inserted
 491          //leave the document as is and don't raise an exception
 492          if ($refChild->uid == $newChild->uid) {
 493              return $newChild;
 494          }
 495  
 496          //if $newChild is a DocumentFragment,
 497          //loop through and insert each node separately
 498          if ($newChild->nodeType == DOMIT_DOCUMENT_FRAGMENT_NODE) {
 499              $total = $newChild->childCount;
 500  
 501              for ($i = 0; $i < $total; $i++) {
 502                  $currChild =& $newChild->childNodes[$i];
 503                  $this->insertBefore($currChild, $refChild);
 504              }
 505  
 506              return $newChild;
 507          }
 508  
 509          //remove $newChild if it already exists
 510          $index = $this->getChildNodeIndex($this->childNodes, $newChild);
 511          if ($index != -1) {
 512              $this->removeChild($newChild);
 513          }
 514  
 515          //find index of $refChild in childNodes
 516          $index = $this->getChildNodeIndex($this->childNodes, $refChild);
 517  
 518          if ($index != -1) {
 519              //reset sibling chain
 520              if ($refChild->previousSibling != null) {
 521                  $refChild->previousSibling->nextSibling =& $newChild;
 522                  $newChild->previousSibling =& $refChild->previousSibling;
 523              }
 524              else {
 525                  $this->firstChild =& $newChild;
 526  
 527                  if ($newChild->previousSibling != null) {
 528                      unset($newChild->previousSibling);
 529                      $newChild->previousSibling = null;
 530                  }
 531              }
 532  
 533              $newChild->parentNode =& $refChild->parentNode;
 534              $newChild->nextSibling =& $refChild;
 535              $refChild->previousSibling =& $newChild;
 536  
 537              //add node to childNodes
 538              $i = $this->childCount;
 539  
 540              while ($i >= 0) {
 541                  if ($i > $index) {
 542                      $this->childNodes[$i] =& $this->childNodes[($i - 1)];
 543                  }
 544                  else if ($i == $index) {
 545                      $this->childNodes[$i] =& $newChild;
 546                  }
 547                  $i--;
 548              }
 549  
 550              $this->childCount++;
 551          }
 552          else {
 553              $this->appendChild($newChild);
 554          }
 555  
 556          $newChild->setOwnerDocument($this);
 557          return $newChild;
 558      } //insertBefore
 559  
 560      /**
 561      * Replaces a node with another
 562      * @param Object The new node
 563      * @param Object The old node
 564      * @return Object The new node
 565      */
 566      function &replaceChild(&$newChild, &$oldChild) {
 567          if ($newChild->nodeType == DOMIT_ATTRIBUTE_NODE) {
 568              DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
 569                  ('Cannot add a node of type ' . get_class($newChild) . ' using replaceChild'));
 570          }
 571          else if ($newChild->nodeType == DOMIT_DOCUMENT_FRAGMENT_NODE) { //if $newChild is a DocumentFragment
 572              //replace the first node then loop through and insert each node separately
 573              $total = $newChild->childCount;
 574  
 575              if ($total > 0) {
 576                  $newRef =& $newChild->lastChild;
 577                  $this->replaceChild($newRef, $oldChild);
 578  
 579                  for ($i = 0; $i < ($total - 1); $i++) {
 580                      $currChild =& $newChild->childNodes[$i];
 581                      $this->insertBefore($currChild, $newRef);
 582                  }
 583              }
 584  
 585              return $newChild;
 586          }
 587          else {
 588              if ($this->hasChildNodes()) {
 589                  //remove $newChild if it already exists
 590                  $index = $this->getChildNodeIndex($this->childNodes, $newChild);
 591                  if ($index != -1) {
 592                      $this->removeChild($newChild);
 593                  }
 594  
 595                  //find index of $oldChild in childNodes
 596                  $index = $this->getChildNodeIndex($this->childNodes, $oldChild);
 597  
 598                  if ($index != -1) {
 599                      $newChild->ownerDocument =& $oldChild->ownerDocument;
 600                      $newChild->parentNode =& $oldChild->parentNode;
 601  
 602                      //reset sibling chain
 603                      if ($oldChild->previousSibling == null) {
 604                          unset($newChild->previousSibling);
 605                          $newChild->previousSibling = null;
 606                      }
 607                      else {
 608                          $oldChild->previousSibling->nextSibling =& $newChild;
 609                          $newChild->previousSibling =& $oldChild->previousSibling;
 610                      }
 611  
 612                      if ($oldChild->nextSibling == null) {
 613                          unset($newChild->nextSibling);
 614                          $newChild->nextSibling = null;
 615                      }
 616                      else {
 617                          $oldChild->nextSibling->previousSibling =& $newChild;
 618                          $newChild->nextSibling =& $oldChild->nextSibling;
 619                      }
 620  
 621                      $this->childNodes[$index] =& $newChild;
 622  
 623                      if ($index == 0) $this->firstChild =& $newChild;
 624                      if ($index == ($this->childCount - 1)) $this->lastChild =& $newChild;
 625  
 626                      $newChild->setOwnerDocument($this);
 627                      return $newChild;
 628                  }
 629              }
 630  
 631              DOMIT_DOMException::raiseException(DOMIT_NOT_FOUND_ERR,
 632                  ('Reference node for replaceChild not found.'));
 633          }
 634      } //replaceChild
 635  
 636      /**
 637      * Removes a node from the childNodes list of the current node
 638      * @param Object The node to be removed
 639      * @return Object The removed node
 640      */
 641      function &removeChild(&$oldChild) {
 642          if ($this->hasChildNodes()) {
 643              //find index of $oldChild in childNodes
 644              $index = $this->getChildNodeIndex($this->childNodes, $oldChild);
 645  
 646              if ($index != -1) {
 647                  //reset sibling chain
 648                  if (($oldChild->previousSibling != null) && ($oldChild->nextSibling != null)) {
 649                      $oldChild->previousSibling->nextSibling =& $oldChild->nextSibling;
 650                      $oldChild->nextSibling->previousSibling =& $oldChild->previousSibling;
 651                  }
 652                  else if (($oldChild->previousSibling != null) && ($oldChild->nextSibling == null)) {
 653                      $this->lastChild =& $oldChild->previousSibling;
 654                      unset($oldChild->previousSibling->nextSibling);
 655                      $oldChild->previousSibling->nextSibling = null;
 656                  }
 657                  else if (($oldChild->previousSibling == null) && ($oldChild->nextSibling != null)) {
 658                      unset($oldChild->nextSibling->previousSibling);
 659                      $oldChild->nextSibling->previousSibling = null;
 660                      $this->firstChild =& $oldChild->nextSibling;
 661                  }
 662                  else if (($oldChild->previousSibling == null) && ($oldChild->nextSibling == null)) {
 663                      unset($this->firstChild);
 664                      $this->firstChild = null;
 665                      unset($this->lastChild);
 666                      $this->lastChild = null;
 667                  }
 668  
 669                  $total = $this->childCount;
 670  
 671                  //remove node from childNodes
 672                  for ($i = 0; $i < $total; $i++) {
 673                      if ($i == ($total - 1)) {
 674                          array_splice($this->childNodes, $i, 1);
 675                      }
 676                      else if ($i >= $index) {
 677                          $this->childNodes[$i] =& $this->childNodes[($i + 1)];
 678                      }
 679                  }
 680  
 681                  $this->childCount--;
 682  
 683                  $oldChild->clearReferences();
 684                  return $oldChild;
 685              }
 686          }
 687  
 688          DOMIT_DOMException::raiseException(DOMIT_NOT_FOUND_ERR,
 689                  ('Target node for removeChild not found.'));
 690      } //removeChild
 691  
 692  
 693      /**
 694      * Searches the element tree for an element with the specified attribute name and value.
 695      * @param string The value of the attribute
 696      * @param string The name of the attribute
 697      * @param boolean True if the first found node is to be returned as a node instead of a nodelist
 698      * @param boolean True if uid is to be considered an attribute
 699      * @return object A NodeList of found elements, or null
 700      */
 701      function &getElementsByAttribute($attrName = 'id', $attrValue = '',
 702                              $returnFirstFoundNode = false, $treatUIDAsAttribute = false) {
 703          require_once (DOMIT_INCLUDE_PATH . 'xml_domit_nodemaps.php');
 704  
 705          $nodelist = new DOMIT_NodeList();
 706  
 707          switch ($this->nodeType) {
 708              case DOMIT_ELEMENT_NODE:
 709                  $this->_getElementsByAttribute($nodelist, $attrName, $attrValue,
 710                                          $returnFirstFoundNode, $treatUIDAsAttribute);
 711                  break;
 712  
 713              case DOMIT_DOCUMENT_NODE:
 714                  if ($this->documentElement != null) {
 715                      $this->documentElement->_getElementsByAttribute($nodelist,
 716                              $attrName, $attrValue, $returnFirstFoundNode, $treatUIDAsAttribute);
 717                  }
 718                  break;
 719          }
 720  
 721          if ($returnFirstFoundNode) {
 722              if ($nodelist->getLength() > 0) {
 723                  return $nodelist->item(0);
 724              }
 725              else {
 726                  $null = null;
 727                  return $null;
 728              }
 729          }
 730          else {
 731              return $nodelist;
 732          }
 733      } //getElementsByAttribute
 734  
 735      /**
 736      * Searches the element tree for an element with the specified attribute name and value.
 737      * @param object The node list of found elements
 738      * @param string The value of the attribute
 739      * @param string The name of the attribute
 740      * @param boolean True if the first found node is to be returned as a node instead of a nodelist
 741      * @param boolean True if uid is to be considered an attribute
 742      * @param boolean True the node has been found
 743      */
 744  	function _getElementsByAttribute(&$nodelist, $attrName, $attrValue,
 745                              $returnFirstFoundNode, $treatUIDAsAttribute, $foundNode = false) {
 746          if (!($foundNode && $returnFirstFoundNode)) {
 747              if (($this->getAttribute($attrName) == $attrValue) ||
 748                  ($treatUIDAsAttribute && ($attrName == 'uid') && ($this->uid == $attrValue))) {
 749                  $nodelist->appendNode($this);
 750                  $foundNode = true;
 751                  if ($returnFirstFoundNode) return;
 752              }
 753  
 754              $total = $this->childCount;
 755  
 756              for ($i = 0; $i < $total; $i++) {
 757                  $currNode =& $this->childNodes[$i];
 758  
 759                  if ($currNode->nodeType == DOMIT_ELEMENT_NODE) {
 760                      $currNode->_getElementsByAttribute($nodelist,
 761                                  $attrName, $attrValue, $returnFirstFoundNode,
 762                                  $treatUIDAsAttribute, $foundNode);
 763                  }
 764  
 765              }
 766          }
 767      } //_getElementsByAttribute
 768  
 769      /**
 770      * Performs an XPath query
 771      * @param string The query pattern
 772      * @return Object A NodeList containing the found nodes
 773      */
 774      function &selectNodes($pattern, $nodeIndex = 0) {
 775          require_once (DOMIT_INCLUDE_PATH . 'xml_domit_xpath.php');
 776  
 777          $xpParser = new DOMIT_XPath();
 778  
 779          return $xpParser->parsePattern($this, $pattern, $nodeIndex);
 780      } //selectNodes
 781  
 782      /**
 783      * Converts the childNodes array into a NodeList object
 784      * @return Object A NodeList containing elements of the childNodes array
 785      */
 786      function &childNodesAsNodeList() {
 787          require_once ('xml_domit_nodemaps.php');
 788          $myNodeList = new DOMIT_NodeList();
 789  
 790          $total = $this->childCount;
 791  
 792          for ($i = 0; $i < $total; $i++) {
 793              $myNodeList->appendNode($this->childNodes[$i]);
 794          }
 795  
 796          return $myNodeList;
 797      } //childNodesAsNodeList
 798  } //DOMIT_ChildNodes_Interface
 799  
 800  /**
 801  * A class representing the DOM Document
 802  *
 803  * @package domit-xmlparser
 804  * @subpackage domit-xmlparser-main
 805  * @author John Heinstein <johnkarl@nbnet.nb.ca>
 806  */
 807  class DOMIT_Document extends DOMIT_ChildNodes_Interface {
 808      /** @var Object The xml declaration processing instruction */
 809      var $xmlDeclaration;
 810      /** @var Object A reference to a DOMIT_DocType object */
 811      var $doctype;
 812      /** @var Object A reference to the root node of the DOM document */
 813      var $documentElement;
 814      /** @var string The parser used to process the DOM document, either "EXPAT" or "SAXY" */
 815      var $parser;
 816      /** @var Object A reference to the DOMIT_DOMImplementation object */
 817      var $implementation;
 818      /** @var boolean True if the DOM document has been modifed since being parsed (NOT YET IMPLEMENTED!) */
 819      var $isModified;
 820      /** @var boolean True if whitespace is to be preserved during parsing */
 821      var $preserveWhitespace = false;
 822      /** @var Array User defined translation table for XML entities; passed to SAXY */
 823      var $definedEntities = array();
 824      /** @var boolean If true, loadXML or parseXML will attempt to detect and repair invalid xml */
 825      var $doResolveErrors = false;
 826      /** @var boolean If true, elements tags will be rendered to string as <element></element> rather than <element/> */
 827      var $doExpandEmptyElementTags = false;
 828      /** @var array A list of exceptions to the empty element expansion rule */
 829      var $expandEmptyElementExceptions = array();
 830      /** @var boolean If true, namespaces will be processed */
 831      var $isNamespaceAware = false;
 832      /** @var int The error code returned by the SAX parser */
 833      var $errorCode = 0;
 834      /** @var string The error string returned by the SAX parser */
 835      var $errorString = '';
 836      /** @var object A reference to a http connection or proxy server, if one is required */
 837      var $httpConnection = null;
 838      /** @var boolean True if php_http_client_generic is to be used instead of PHP get_file_contents to retrieve xml data */
 839      var $doUseHTTPClient = false;
 840      /** @var array An array of namespacesURIs mapped to prefixes */
 841      var $namespaceURIMap = array();
 842  
 843      /**
 844      * DOM Document constructor
 845      */
 846  	function DOMIT_Document() {
 847          $this->_constructor();
 848          $this->xmlDeclaration = null;
 849          $this->doctype = null;
 850          $this->documentElement = null;
 851          $this->nodeType = DOMIT_DOCUMENT_NODE;
 852          $this->nodeName = '#document';
 853          $this->ownerDocument =& $this;
 854          $this->parser = '';
 855          $this->implementation = new DOMIT_DOMImplementation();
 856      } //DOMIT_Document
 857  
 858      /**
 859      * Specifies whether DOMIT! will try to fix invalid XML before parsing begins
 860      * @param boolean True if errors are to be resolved
 861      */
 862  	function resolveErrors($truthVal) {
 863          $this->doResolveErrors = $truthVal;
 864      } //resolveErrors
 865  
 866      /**
 867      * Specifies whether DOMIT! processes namespace information
 868      * @param boolean True if namespaces are to be processed
 869      */
 870  	function setNamespaceAwareness($truthVal) {
 871          $this->isNamespaceAware = $truthVal;
 872      } //setNamespaceAwareness
 873  
 874      /**
 875      * Specifies whether DOMIT! preserves whitespace when parsing
 876      * @param boolean True if whitespace is to be preserved
 877      */
 878  	function preserveWhitespace($truthVal) {
 879          $this->preserveWhitespace = $truthVal;
 880      } //preserveWhitespace
 881  
 882      /**
 883      * Specifies the parameters of the http conection used to obtain the xml data
 884      * @param string The ip address or domain name of the connection
 885      * @param string The path of the connection
 886      * @param int The port that the connection is listening on
 887      * @param int The timeout value for the connection
 888      * @param string The user name, if authentication is required
 889      * @param string The password, if authentication is required
 890      */
 891  	function setConnection($host, $path = '/', $port = 80, $timeout = 0, $user = null, $password = null) {
 892          require_once (DOMIT_INCLUDE_PATH . 'php_http_client_generic.php');
 893  
 894          $this->httpConnection = new php_http_client_generic($host, $path, $port, $timeout, $user, $password);
 895      } //setConnection
 896  
 897      /**
 898      * Specifies basic authentication for an http connection
 899      * @param string The user name
 900      * @param string The password
 901      */
 902  	function setAuthorization($user, $password) {
 903          $this->httpConnection->setAuthorization($user, $password);
 904      } //setAuthorization
 905  
 906      /**
 907      * Specifies that a proxy is to be used to obtain the xml data
 908      * @param string The ip address or domain name of the proxy
 909      * @param string The path to the proxy
 910      * @param int The port that the proxy is listening on
 911      * @param int The timeout value for the connection
 912      * @param string The user name, if authentication is required
 913      * @param string The password, if authentication is required
 914      */
 915  	function setProxyConnection($host, $path = '/', $port = 80, $timeout = 0, $user = null, $password = null) {
 916          require_once (DOMIT_INCLUDE_PATH . 'php_http_proxy.php');
 917  
 918          $this->httpConnection = new php_http_proxy($host, $path, $port, $timeout, $user, $password);
 919      } //setProxyConnection
 920  
 921      /**
 922      * Specifies basic authentication for the proxy
 923      * @param string The user name
 924      * @param string The password
 925      */
 926  	function setProxyAuthorization($user, $password) {
 927          $this->httpConnection->setProxyAuthorization($user, $password);
 928      } //setProxyAuthorization
 929  
 930      /**
 931      * Specifies whether an HTTP client should be used to establish a connection
 932      * @param boolean True if an HTTP client is to be used to establish the connection
 933      */
 934  	function useHTTPClient($truthVal) {
 935          $this->doUseHTTPClient = $truthVal;
 936      } //useHTTPClient
 937  
 938      /**
 939      * Returns the error code from the underlying SAX parser
 940      * @return int The error code
 941      */
 942  	function getErrorCode() {
 943          return $this->errorCode;
 944      } //getErrorCode
 945  
 946      /**
 947      * Returns the error string from the underlying SAX parser
 948      * @return string The error string
 949      */
 950  	function getErrorString() {
 951          return $this->errorString;
 952      } //getErrorString
 953  
 954      /**
 955      * Specifies whether elements tags will be rendered to string as <element></element> rather than <element/>
 956      * @param boolean True if the expanded form is to be used
 957      * @param mixed An array of tag names that should be excepted from expandEmptyElements rule (optional)
 958      */
 959  	function expandEmptyElementTags($truthVal, $expandEmptyElementExceptions = false) {
 960          $this->doExpandEmptyElementTags = $truthVal;
 961  
 962          if (is_array($expandEmptyElementExceptions)) {
 963              $this->expandEmptyElementExceptions = $expandEmptyElementExceptions;
 964          }
 965      } //expandEmptyElementTags
 966  
 967      /**
 968      * Set the specified node as document element
 969      * @param Object The node that is to become document element
 970      * @return Object The new document element
 971      */
 972      function &setDocumentElement(&$node) {
 973          if ($node->nodeType == DOMIT_ELEMENT_NODE) {
 974              if ($this->documentElement == null) {
 975                  parent::appendChild($node);
 976              }
 977              else {
 978                  parent::replaceChild($node, $this->documentElement);
 979              }
 980  
 981              $this->documentElement =& $node;
 982          }
 983          else {
 984              DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
 985                  ('Cannot add a node of type ' . get_class($node) . ' as a Document Element.'));
 986          }
 987  
 988          return $node;
 989      } //setDocumentElement
 990  
 991      /**
 992      * Imports a node (and optionally its children) from another DOM Document
 993      * @param object A reference to the node to be imported
 994      * @param boolean True if the children of the imported node are also to be imported
 995      * @return object The imported node (and, if specified, its children)
 996      */
 997      function &importNode(&$importedNode, $deep = true) {
 998          $parentNode = null;
 999          return $this->_importNode($parentNode, $importedNode, $deep);
1000      } //importNode
1001  
1002  
1003      /**
1004      * Imports a node (and optionally its children) from another DOM Document
1005      * @param object A reference to the parent of the node to be imported
1006      * @param object A reference to the node to be imported
1007      * @param boolean True if the children of the imported node are also to be imported
1008      * @return object The imported node if it is the top level node, otherwise null
1009      */
1010      function &_importNode(&$parentNode, &$sourceNode, $deep) {
1011          $hasChildren = false;
1012  
1013          switch ($sourceNode->nodeType) {
1014              case DOMIT_ELEMENT_NODE:
1015                  $hasChildren = true;
1016  
1017                  if ($this->isNamespaceAware) {
1018                      $importedNode =& $this->createElementNS($sourceNode->namespaceURI,
1019                                  ($sourceNode->prefix . ":" . $sourceNode->localName));
1020                  }
1021                  else {
1022                      $importedNode =& $this->createElement($sourceNode->nodeName);
1023                  }
1024  
1025                  $attrNodes =& $sourceNode->attributes;
1026                  $total = $attrNodes->getLength();
1027  
1028                  for ($i = 0; $i < $total; $i++) {
1029                      $attrNode =& $attrNodes->item($i);
1030  
1031                      if ($this->isNamespaceAware) {
1032                          $importedNode->setAttributeNS($attrNode->namespaceURI,
1033                              ($attrNode->prefix . ":" . $attrNode->localName), $attrNode->nodeValue);
1034                      }
1035                      else {
1036                          $importedNode->setAttribute($attrNode->nodeName, $attrNode->nodeValue);
1037                      }
1038                  }
1039  
1040                  break;
1041  
1042              case DOMIT_ATTRIBUTE_NODE:
1043                  if ($this->isNamespaceAware) {
1044                      $importedNode =& $this->createAttributeNS($sourceNode->namespaceURI,
1045                                  ($sourceNode->prefix . ":" . $sourceNode->localName));
1046                  }
1047                  else {
1048                      $importedNode =& $this->createAttribute($sourceNode->nodeValue);
1049                  }
1050                  break;
1051  
1052              case DOMIT_TEXT_NODE:
1053                  $importedNode =& $this->createTextNode($sourceNode->nodeValue);
1054                  break;
1055  
1056              case DOMIT_CDATA_SECTION_NODE:
1057                  $importedNode =& $this->createCDATASection($sourceNode->nodeValue);
1058                  break;
1059  
1060              case DOMIT_COMMENT_NODE:
1061                  $importedNode =& $this->createComment($sourceNode->nodeValue);
1062                  break;
1063  
1064              case DOMIT_DOCUMENT_FRAGMENT_NODE:
1065                  $hasChildren = true;
1066                  $importedNode =& $this->createDocumentFragment();
1067                  break;
1068  
1069              case DOMIT_PROCESSING_INSTRUCTION_NODE:
1070                  $importedNode =& $this->createProcessingInstruction($sourceNode->nodeName,
1071                                                                      $sourceNode->nodeValue);
1072                  break;
1073  
1074              case DOMIT_DOCUMENT_NODE:
1075              case DOMIT_DOCUMENT_TYPE_NODE:
1076                  DOMIT_DOMException::raiseException(DOMIT_NOT_SUPPORTED_ERR,
1077                      ('Method importNode cannot be called by class ' . get_class($this)));
1078                  break;
1079          }
1080  
1081          if ($hasChildren && $deep) {
1082              $total = $sourceNode->childCount;
1083  
1084              for ($i = 0; $i < $total; $i++) {
1085                  $importedNode->appendChild(
1086                          $this->_importNode($importedNode, $sourceNode->childNodes[$i], $deep));
1087              }
1088          }
1089  
1090          return $importedNode;
1091      } //_importNode
1092  
1093      /**
1094      * Appends a node to the childNodes list of the current node
1095      * @param Object The node to be appended
1096      * @return Object The appended node
1097      */
1098      function &appendChild(&$node) {
1099          switch ($node->nodeType) {
1100              case DOMIT_ELEMENT_NODE:
1101                  if ($this->documentElement == null) {
1102                      parent::appendChild($node);
1103                      $this->setDocumentElement($node);
1104                  }
1105                  else {
1106                      //error thrown if documentElement already exists!
1107                      DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
1108                          ('Cannot have more than one root node (documentElement) in a DOMIT_Document.'));
1109                  }
1110                  break;
1111  
1112              case DOMIT_PROCESSING_INSTRUCTION_NODE:
1113              case DOMIT_COMMENT_NODE:
1114                  parent::appendChild($node);
1115                  break;
1116  
1117                 case DOMIT_DOCUMENT_TYPE_NODE:
1118                     if ($this->doctype == null) {
1119                      parent::appendChild($node);
1120                  }
1121                  else {
1122                      DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
1123                          ('Cannot have more than one doctype node in a DOMIT_Document.'));
1124                  }
1125                     break;
1126  
1127              case DOMIT_DOCUMENT_FRAGMENT_NODE:
1128                  $total = $node->childCount;
1129  
1130                  for ($i = 0; $i < $total; $i++) {
1131                      $currChild =& $node->childNodes[$i];
1132                      $this->appendChild($currChild);
1133                  }
1134                  break;
1135  
1136                 default:
1137                     DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
1138                      ('Cannot add a node of type ' . get_class($node) . ' to a DOMIT_Document.'));
1139          }
1140  
1141          return $node;
1142      } //appendChild
1143  
1144      /**
1145      * Replaces a node with another
1146      * @param Object The new node
1147      * @param Object The old node
1148      * @return Object The new node
1149      */
1150      function &replaceChild(&$newChild, &$oldChild) {
1151          if ($this->nodeType == DOMIT_DOCUMENT_FRAGMENT_NODE) {
1152              $total = $newChild->childCount;
1153  
1154              if ($total > 0) {
1155                  $newRef =& $newChild->lastChild;
1156                  $this->replaceChild($newRef, $oldChild);
1157  
1158                  for ($i = 0; $i < ($total - 1); $i++) {
1159                      $currChild =& $newChild->childNodes[$i];
1160                      parent::insertBefore($currChild, $newRef);
1161                  }
1162              }
1163          }
1164          else {
1165              if (($this->documentElement != null) && ($oldChild->uid == $this->documentElement->uid)) {
1166                  if ($newChild->nodeType == DOMIT_ELEMENT_NODE) {
1167                      //replace documentElement with new node
1168                      $this->setDocumentElement($newChild);
1169                  }
1170                  else {
1171                      DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
1172                          ('Cannot replace Document Element with a node of class ' . get_class($newChild)));
1173                  }
1174              }
1175              else {
1176                  switch ($newChild->nodeType) {
1177                      case DOMIT_ELEMENT_NODE:
1178                          if ($this->documentElement != null) {
1179                              DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
1180                                  ('Cannot have more than one root node (documentElement) in a DOMIT_Document.'));
1181                          }
1182                          else {
1183                              parent::replaceChild($newChild, $oldChild);
1184                          }
1185                          break;
1186  
1187                      case DOMIT_PROCESSING_INSTRUCTION_NODE:
1188                      case DOMIT_COMMENT_NODE:
1189                          parent::replaceChild($newChild, $oldChild);
1190                          break;
1191  
1192                       case DOMIT_DOCUMENT_TYPE_NODE:
1193                           if ($this->doctype != null) {
1194                              if ($this->doctype->uid == $oldChild->uid) {
1195                                  parent::replaceChild($newChild, $oldChild);
1196                              }
1197                              else {
1198                                  DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
1199                                      ('Cannot have more than one doctype node in a DOMIT_Document.'));
1200                              }
1201                          }
1202                          else {
1203                              parent::replaceChild($newChild, $oldChild);
1204                          }
1205                           break;
1206  
1207                        default:
1208                            DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
1209                              ('Nodes of class ' . get_class($newChild) . ' cannot be children of a DOMIT_Document.'));
1210                  }
1211              }
1212          }
1213  
1214          return $newChild;
1215      } //replaceChild
1216  
1217      /**
1218      * Inserts a node to the childNodes list of the current node
1219      * @param Object The node to be inserted
1220      * @param Object The node before which the insertion is to occur
1221      * @return Object The inserted node
1222      */
1223      function &insertBefore(&$newChild, &$refChild) {
1224          $type = $newChild->nodeType;
1225  
1226          if ($this->nodeType == DOMIT_DOCUMENT_FRAGMENT_NODE) {
1227              $total = $newChild->childCount;
1228  
1229              for ($i = 0; $i < $total; $i++) {
1230                  $currChild =& $newChild->childNodes[$i];
1231                  $this->insertBefore($currChild, $refChild);
1232              }
1233          }
1234          else if ($type == DOMIT_ELEMENT_NODE) {
1235              if ($this->documentElement == null) {
1236                  parent::insertBefore($newChild, $refChild);
1237                  $this->setDocumentElement($newChild);
1238              }
1239              else {
1240                  //error thrown if documentElement already exists!
1241                  DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
1242                      ('Cannot have more than one root node (documentElement) in a DOMIT_Document.'));
1243              }
1244          }
1245          else if ($type == DOMIT_PROCESSING_INSTRUCTION_NODE) {
1246              parent::insertBefore($newChild, $refChild);
1247          }
1248          else if ($type == DOMIT_DOCUMENT_TYPE_NODE) {
1249              if ($this->doctype == null) {
1250                  parent::insertBefore($newChild, $refChild);
1251              }
1252              else {
1253                  DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
1254                      ('Cannot have more than one doctype node in a DOMIT_Document.'));
1255              }
1256          }
1257          else {
1258              DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
1259                  ('Cannot insert a node of type ' . get_class($newChild) . ' to a DOMIT_Document.'));
1260          }
1261  
1262          return $newChild;
1263      } //insertBefore
1264  
1265      /**
1266      * Removes a node from the childNodes list of the current node
1267      * @param Object The node to be removed
1268      * @return Object The removed node
1269      */
1270      function &removeChild(&$oldChild) {
1271          if ($this->nodeType == DOMIT_DOCUMENT_FRAGMENT_NODE) {
1272              $total = $oldChild->childCount;
1273  
1274              for ($i = 0; $i < $total; $i++) {
1275                  $currChild =& $oldChild->childNodes[$i];
1276                  $this->removeChild($currChild);
1277              }
1278          }
1279          else {
1280              if (($this->documentElement != null) && ($oldChild->uid == $this->documentElement->uid)) {
1281                  parent::removeChild($oldChild);
1282                  $this->documentElement = null;
1283              }
1284              else {
1285                  parent::removeChild($oldChild);
1286              }
1287          }
1288  
1289          $oldChild->clearReferences();
1290          return $oldChild;
1291      } //removeChild
1292  
1293  
1294      /**
1295      * Creates a new DOMIT_DocumentFragment node
1296      * @return Object The new document fragment node
1297      */
1298      function &createDocumentFragment() {
1299          $node = new DOMIT_DocumentFragment();
1300          $node->ownerDocument =& $this;
1301  
1302          return $node;
1303      } //createDocumentFragment
1304  
1305      /**
1306      * Creates a new DOMIT_Attr node
1307      * @param string The name of the attribute
1308      * @return Object The new attribute node
1309      */
1310      function &createAttribute($name) {
1311          $node = new DOMIT_Attr($name);
1312  
1313          return $node;
1314      } //createAttribute
1315  
1316      /**
1317      * Creates a new DOMIT_Attr node (namespace aware)
1318      * @param string The namespaceURI of the attribute
1319      * @param string The qualifiedName of the attribute
1320      * @return Object The new attribute node
1321      */
1322      function &createAttributeNS($namespaceURI, $qualifiedName) {
1323          $node = new DOMIT_Attr($qualifiedName);
1324          $node->namespaceURI = $namespaceURI;
1325  
1326          $colonIndex = strpos($qualifiedName, ":");
1327  
1328          if ($colonIndex !== false) {
1329              $node->prefix = substr($qualifiedName, 0, $colonIndex);
1330              $node->localName = substr($qualifiedName, ($colonIndex + 1));
1331          }
1332          else {
1333              $node->prefix = '';
1334              $node->localName = $qualifiedName;
1335          }
1336  
1337          return $node;
1338      } //createAttributeNS
1339  
1340      /**
1341      * Creates a new DOMIT_Element node
1342      * @param string The tag name of the element
1343      * @return Object The new element
1344      */
1345      function &createElement($tagName) {
1346          $node = new DOMIT_Element($tagName);
1347          $node->ownerDocument =& $this;
1348  
1349          return $node;
1350      } //createElement
1351  
1352      /**
1353      * Creates a new DOMIT_Element node (namespace aware)
1354      * @param string The namespaceURI of the element
1355      * @param string The qualifiedName of the element
1356      * @return Object The new element
1357      */
1358      function &createElementNS($namespaceURI, $qualifiedName) {
1359          $node = new DOMIT_Element($qualifiedName);
1360  
1361          $colonIndex = strpos($qualifiedName, ":");
1362  
1363          if ($colonIndex !== false) {
1364              $node->prefix = substr($qualifiedName, 0, $colonIndex);
1365              $node->localName = substr($qualifiedName, ($colonIndex + 1));
1366          }
1367          else {
1368              $node->prefix = '';
1369              $node->localName = $qualifiedName;
1370          }
1371  
1372          $node->namespaceURI = $namespaceURI;
1373  
1374          $node->ownerDocument =& $this;
1375  
1376          return $node;
1377      } //createElementNS
1378  
1379      /**
1380      * Creates a new DOMIT_Text node
1381      * @param string The text of the node
1382      * @return Object The new text node
1383      */
1384      function &createTextNode($data) {
1385          $node = new DOMIT_TextNode($data);
1386          $node->ownerDocument =& $this;
1387  
1388          return $node;
1389      } //createTextNode
1390  
1391      /**
1392      * Creates a new DOMIT_CDataSection node
1393      * @param string The text of the CDATASection
1394      * @return Object The new CDATASection node
1395      */
1396      function &createCDATASection($data) {
1397          $node = new DOMIT_CDATASection($data);
1398          $node->ownerDocument =& $this;
1399  
1400          return $node;
1401      } //createCDATASection
1402  
1403      /**
1404      * Creates a new DOMIT_Comment node
1405      * @param string The comment text
1406      * @return Object The new comment node
1407      */
1408      function &createComment($text) {
1409          $node = new DOMIT_Comment($text);
1410          $node->ownerDocument =& $this;
1411  
1412          return $node;
1413      } //createComment
1414  
1415      /**
1416      * Creates a new DOMIT_ProcessingInstruction node
1417      * @param string The target of the processing instruction
1418      * @param string The data of the processing instruction
1419      * @return Object The new processing instruction node
1420      */
1421      function &createProcessingInstruction($target, $data) {
1422          $node = new DOMIT_ProcessingInstruction($target, $data);
1423          $node->ownerDocument =& $this;
1424  
1425          return $node;
1426      } //createProcessingInstruction
1427  
1428      /**
1429      * Retrieves a NodeList of child elements with the specified tag name
1430      * @param string The matching element tag name
1431      * @return Object A NodeList of found elements
1432      */
1433      function &getElementsByTagName($tagName) {
1434          $nodeList = new DOMIT_NodeList();
1435  
1436          if ($this->documentElement != null) {
1437              $this->documentElement->getNamedElements($nodeList, $tagName);
1438          }
1439  
1440          return $nodeList;
1441      } //getElementsByTagName
1442  
1443      /**
1444      * Retrieves a NodeList of child elements with the specified namespaceURI and localName
1445      * @param string The matching namespaceURI
1446      * @param string The matching localName
1447      * @return Object A NodeList of found elements
1448      */
1449      function &getElementsByTagNameNS($namespaceURI, $localName) {
1450          $nodeList = new DOMIT_NodeList();
1451  
1452          if ($this->documentElement != null) {
1453              $this->documentElement->getNamedElementsNS($nodeList, $namespaceURI, $localName);
1454          }
1455  
1456          return $nodeList;
1457      } //getElementsByTagNameNS
1458  
1459      /**
1460      * Returns the element whose ID is given by elementId.
1461      * @param string The id of the matching element
1462      * @param boolean True if XML spec is to be strictly adhered to (only attributes xml:id are considered valid)
1463      * @return Object The found element or null
1464      */
1465      function &getElementByID($elementID, $isStrict = true) {
1466          if ($this->isNamespaceAware) {
1467              if ($this->documentElement != null) {
1468                  $targetAttrNode =& $this->documentElement->_getElementByID($elementID, $isStrict);
1469                  return $targetAttrNode->ownerElement;
1470              }
1471  
1472              $null = null;
1473              return $null;
1474          }
1475          else {
1476              DOMIT_DOMException::raiseException(DOMIT_INVALID_ACCESS_ERR,
1477                   'Namespace awareness must be enabled to use method getElementByID');
1478          }
1479      } //getElementByID
1480  
1481      /**
1482      * Retrieves an element or DOMIT_NodeList of elements corresponding to an Xpath-like expression.
1483      * @param string The query pattern
1484      * @param int If a single node is to be returned (rather than the entire NodeList) the index of that node
1485      * @return mixed A NodeList or single node that matches the pattern
1486      */
1487      function &getElementsByPath($pattern, $nodeIndex = 0) {
1488          require_once (DOMIT_INCLUDE_PATH . 'xml_domit_getelementsbypath.php');
1489  
1490          $gebp = new DOMIT_GetElementsByPath();
1491          $myResponse =& $gebp->parsePattern($this, $pattern, $nodeIndex);
1492  
1493          return $myResponse;
1494      } //getElementsByPath
1495  
1496      /**
1497      * Retrieves an element or DOMIT_NodeList of elements corresponding to an Xpath-like attribute expression (NOT YET IMPLEMENTED!)
1498      * @param string The query pattern
1499      * @param int If a single node is to be returned (rather than the entire NodeList) the index of that node
1500      * @return mixed A NodeList or single node that matches the pattern
1501      */
1502      function &getElementsByAttributePath($pattern, $nodeIndex = 0) {
1503          require_once (DOMIT_INCLUDE_PATH . 'xml_domit_getelementsbypath.php');
1504  
1505          $gabp = new DOMIT_GetElementsByAttributePath();
1506          $myResponse =& $gabp->parsePattern($this, $pattern, $nodeIndex);
1507  
1508          return $myResponse;
1509      } //getElementsByAttributePath
1510  
1511      /**
1512      * Retrieves all child nodes of the specified nodeType
1513      * @param string The nodeType of matching nodes
1514      * @param Object The root node of the search
1515      * @return Object A NodeList containing found nodes
1516      */
1517      function &getNodesByNodeType($type, &$contextNode) {
1518          $nodeList = new DOMIT_NodeList();
1519  
1520          if (($type == DOMIT_DOCUMENT_NODE) || ($contextNode->nodeType == DOMIT_DOCUMENT_NODE)){
1521              $nodeList->appendNode($this);
1522          }
1523          else if ($contextNode->nodeType == DOMIT_ELEMENT_NODE) {
1524              $contextNode->getTypedNodes($nodeList, $type);
1525          }
1526          else if ($contextNode->uid == $this->uid) {
1527              if ($this->documentElement != null) {
1528                  if ($type == DOMIT_ELEMENT_NODE) {
1529                      $nodeList->appendNode($this->documentElement);
1530                  }
1531  
1532                  $this->documentElement->getTypedNodes($nodeList, $type);
1533              }
1534          }
1535  
1536          return $nodeList;
1537      } //getNodesByNodeType
1538  
1539      /**
1540      * Retrieves all child nodes of the specified nodeValue
1541      * @param string The nodeValue of matching nodes
1542      * @param Object The root node of the search
1543      * @return Object A NodeList containing found nodes
1544      */
1545      function &getNodesByNodeValue($value, &$contextNode) {
1546          $nodeList = new DOMIT_NodeList();
1547  
1548           if ($contextNode->uid == $this->uid) {
1549               if ($this->nodeValue == $value) {
1550                   $nodeList->appendNode($this);
1551               }
1552           }
1553  
1554          if ($this->documentElement != null) {
1555              $this->documentElement->getValuedNodes($nodeList, $value);
1556          }
1557  
1558          return $nodeList;
1559      } //getNodesByNodeValue
1560  
1561      /**
1562      * Parses an xml string
1563      * @param string The xml text to be parsed
1564      * @param boolean True if SAXY is to be used instead of Expat
1565      * @param boolean False if CDATA Section are to be generated as Text nodes
1566      * @param boolean True if onLoad is to be called on each node after parsing
1567      * @return boolean True if parsing is successful
1568      */
1569  	function parseXML($xmlText, $useSAXY = true, $preserveCDATA = true, $fireLoadEvent = false) {
1570          require_once (DOMIT_INCLUDE_PATH . 'xml_domit_utilities.php');
1571  
1572          if ($this->doResolveErrors) {
1573              require_once (DOMIT_INCLUDE_PATH . 'xml_domit_doctor.php');
1574              $xmlText = DOMIT_Doctor::fixAmpersands($xmlText);
1575          }
1576  
1577          if (DOMIT_Utilities::validateXML($xmlText)) {
1578              $domParser = new DOMIT_Parser();
1579  
1580              if ($useSAXY || (!function_exists('xml_parser_create'))) {
1581                  //use SAXY parser to populate xml tree
1582                  $this->parser = 'SAXY';
1583                  $success = $domParser->parseSAXY($this, $xmlText, $preserveCDATA, $this->definedEntities);
1584              }
1585              else {
1586                  //use Expat parser to populate xml tree
1587                  $this->parser = 'EXPAT';
1588                  $success = $domParser->parse($this, $xmlText, $preserveCDATA);
1589              }
1590  
1591              if ($fireLoadEvent && ($this->documentElement != null)) $this->load($this->documentElement);
1592  
1593              return $success;
1594          }
1595          else {
1596              return false;
1597          }
1598      } //parseXML
1599  
1600      /**
1601      * Parses an xml file
1602      * @param string The xml file to be parsed
1603      * @param boolean True if SAXY is to be used instead of Expat
1604      * @param boolean False if CDATA Section are to be generated as Text nodes
1605      * @param boolean True if onLoad is to be called on each node after parsing
1606      * @return boolean True if parsing is successful
1607      */
1608  	function loadXML($filename, $useSAXY = true, $preserveCDATA = true, $fireLoadEvent = false) {
1609          $xmlText = $this->getTextFromFile($filename);
1610  
1611          return $this->parseXML($xmlText, $useSAXY, $preserveCDATA, $fireLoadEvent);
1612      } //loadXML
1613  
1614      /**
1615      * Establishes a connection, given an url
1616      * @param string The url of the data
1617      */
1618  	function establishConnection($url) {
1619          require_once (DOMIT_INCLUDE_PATH . 'php_http_client_generic.php');
1620  
1621          $host = php_http_connection::formatHost($url);
1622          $host = substr($host, 0, strpos($host, '/'));
1623  
1624          $this->setConnection($host);
1625      } //establishConnection
1626  
1627      /**
1628      * Retrieves text from a file
1629      * @param string The file path
1630      * @return string The text contained in the file
1631      */
1632  	function getTextFromFile($filename) {
1633          if ($this->doUseHTTPClient && (substr($filename, 0, 5) == 'http:')) {
1634              $this->establishConnection($filename);
1635          }
1636  
1637          if ($this->httpConnection != null) {
1638              $response =& $this->httpConnection->get($filename);
1639  
1640              $this->httpConnection->disconnect();
1641              return $response->getResponse();
1642          }
1643          else if (function_exists('file_get_contents')) {
1644              //if (file_exists($filename)) {
1645                  return file_get_contents($filename);
1646              //}
1647          }
1648          else {
1649              require_once (DOMIT_INCLUDE_PATH . 'php_file_utilities.php');
1650  
1651              $fileContents =& php_file_utilities::getDataFromFile($filename, 'r');
1652              return $fileContents;
1653          }
1654  
1655          return '';
1656      } //getTextFromFile
1657  
1658      /**
1659      * Saves the current DOM document as an xml file
1660      * @param string The path of the xml file
1661      * @param boolean True if xml text is to be normalized before saving
1662      * @return boolean True if save is successful
1663      */
1664  	function saveXML($filename, $normalized = false) {
1665          if ($normalized) {
1666              $stringRep = $this->toNormalizedString(false, true);
1667          }
1668          else {
1669              $stringRep = $this->toString(false, true);
1670          }
1671  
1672          return $this->saveTextToFile($filename, $stringRep);
1673      } //saveXML
1674  
1675      /**
1676      * Saves text to a file
1677      * @param string The file path
1678      * @param string The text to be saved
1679      * @return boolean True if the save is successful
1680      */
1681  	function saveTextToFile($filename, $text) {
1682          if (function_exists('file_put_contents')) {
1683              file_put_contents($filename, $text);
1684          }
1685          else {
1686              require_once (DOMIT_INCLUDE_PATH . 'php_file_utilities.php');
1687              php_file_utilities::putDataToFile($filename, $text, 'w');
1688          }
1689  
1690          return (file_exists($filename) && is_writable($filename));
1691      } //saveTextToFile
1692  
1693      /**
1694      * Indicates the SAX parser used to parse the current document
1695      * @return string Either "SAXY" or "EXPAT"
1696      */
1697  	function parsedBy() {
1698          return $this->parser;
1699      } //parsedBy
1700  
1701      /**
1702      * Returns the concatented text of the current node and its children
1703      * @return string The concatented text of the current node and its children
1704      */
1705  	function getText() {
1706          if ($this->documentElement != null) {
1707              $root =& $this->documentElement;
1708              return $root->getText();
1709          }
1710  
1711          return '';
1712      } //getText
1713  
1714      /**
1715      * Returns a doctype object
1716      * @return mixed The doctype object, or null if none exists
1717      */
1718  	function getDocType() {
1719          return $this->doctype;
1720      } //getDocType
1721  
1722      /**
1723      * Returns the xml declaration processing instruction
1724      * @return mixed The xml declaration processing instruction, or null if none exists
1725      */
1726  	function getXMLDeclaration() {
1727          return $this->xmlDeclaration;
1728      } //getXMLDeclaration
1729  
1730      /**
1731      * Returns a reference to the DOMIT_DOMImplementation object
1732      * @return Object A reference to the DOMIT_DOMImplementation object
1733      */
1734      function &getDOMImplementation() {
1735          return $this->implementation;
1736      } //getDOMImplementation
1737  
1738      /**
1739      * Manages the firing of the onLoad() event
1740      * @param Object The parent node of the current recursion
1741      */
1742  	function load(&$contextNode) {
1743          $total = $contextNode->childCount;
1744  
1745          for ($i = 0; $i < $total; $i++) {
1746              $currNode =& $contextNode->childNodes[$i];
1747              $currNode->ownerDocument->load($currNode);
1748          }
1749  
1750          $contextNode->onLoad();
1751      } //load
1752  
1753      /**
1754      * Returns the current version of DOMIT!
1755      * @return Object The current version of DOMIT!
1756      */
1757  	function getVersion() {
1758          return DOMIT_VERSION;
1759      } //getVersion
1760  
1761      /**
1762      * Appends an array of entity mappings to the existing translation table
1763      *
1764      * Intended mainly to facilitate the conversion of non-ASCII entities into equivalent characters
1765      *
1766      * @param array A list of entity mappings in the format: array('&amp;' => '&');
1767      */
1768  	function appendEntityTranslationTable($table) {
1769          $this->definedEntities = $table;
1770  
1771          global $DOMIT_defined_entities_flip;
1772          $DOMIT_defined_entities_flip = array_flip($table);
1773      } //appendEntityTranslationTable
1774  
1775      /**
1776      * Generates an array representation of the node and its children
1777      * @return Array A representation of the node and its children
1778      */
1779  	function toArray() {
1780          $arReturn = array($this->nodeName => array());
1781          $total = $this->childCount;
1782  
1783          for ($i = 0; $i < $total; $i++) {
1784              $arReturn[$this->nodeName][$i] = $this->childNodes[$i]->toArray();
1785          }
1786  
1787          return $arReturn;
1788      } //toArray
1789  
1790      /**
1791      * Copies a node and/or its children
1792      * @param boolean True if all child nodes are also to be cloned
1793      * @return Object A copy of the node and/or its children
1794      */
1795      function &cloneNode($deep = false) {
1796          $className = get_class($this);
1797          $clone = new $className($this->nodeName);
1798  
1799          if ($deep) {
1800              $total = $this->childCount;
1801  
1802              for ($i = 0; $i < $total; $i++) {
1803                  $currentChild =& $this->childNodes[$i];
1804                  $clone->appendChild($currentChild->cloneNode($deep));
1805  
1806                  if ($currentChild->nodeType == DOMIT_DOCUMENT_TYPE_NODE) {
1807                      $clone->doctype =& $clone->childNodes[$i];
1808                  }
1809  
1810                  if (($currentChild->nodeType == DOMIT_PROCESSING_INSTRUCTION_NODE) &&
1811                          ($currentChild->getTarget() == 'xml')) {
1812                      $clone->xmlDeclaration =& $clone->childNodes[$i];
1813                  }
1814              }
1815          }
1816  
1817          return $clone;
1818      } //cloneNode
1819  
1820      /**
1821      * Generates a string representation of the node and its children
1822      * @param boolean True if HTML readable output is desired
1823      * @param boolean True if illegal xml characters in text nodes and attributes should be converted to entities
1824      * @return string The string representation
1825      */
1826  	function toString($htmlSafe = false, $subEntities = false) {
1827          $result = '';
1828          $total = $this->childCount;
1829  
1830          for ($i = 0; $i < $total; $i++) {
1831              $result .= $this->childNodes[$i]->toString(false, $subEntities);
1832          }
1833  
1834          if ($htmlSafe) $result = $this->forHTML($result);
1835  
1836          return $result;
1837      } //toString
1838  } //DOMIT_Document
1839  
1840  /**
1841  * A class representing the DOM Element
1842  *
1843  * @package domit-xmlparser
1844  * @subpackage domit-xmlparser-main
1845  * @author John Heinstein <johnkarl@nbnet.nb.ca>
1846  */
1847  class DOMIT_Element extends DOMIT_ChildNodes_Interface {
1848      /** @var array An array of namespacesURIs mapped to prefixes */
1849      var $namespaceURIMap = array();
1850  
1851      /**
1852      * DOM Element constructor
1853      * @param string The tag name of the element
1854      */
1855  	function DOMIT_Element($tagName) {
1856          $this->_constructor();
1857          $this->nodeType = DOMIT_ELEMENT_NODE;
1858          $this->nodeName = $tagName;
1859          $this->attributes = new DOMIT_NamedNodeMap_Attr();
1860          $this->childNodes = array();
1861      } //DOMIT_Element
1862  
1863      /**
1864      * Returns the tag name of the element
1865      * @return string The tag name of the element
1866      */
1867  	function getTagName() {
1868          return $this->nodeName;
1869      } //getTagName
1870  
1871      /**
1872      * Adds elements with the specified tag name to a NodeList collection
1873      * @param Object The NodeList collection
1874      * @param string The tag name of matching elements
1875      */
1876  	function getNamedElements(&$nodeList, $tagName) {
1877          if (($this->nodeName == $tagName) || ($tagName == '*')) {
1878              $nodeList->appendNode($this);
1879          }
1880  
1881          $total = $this->childCount;
1882  
1883          for ($i = 0; $i < $total; $i++) {
1884              $this->childNodes[$i]->getNamedElements($nodeList, $tagName);
1885          }
1886      } //getNamedElements
1887  
1888      /**
1889      * Creates an xmlns declaration at the current element
1890      * @param array An array of namespace declarations in the scope of the current element
1891      */
1892  	function declareNamespace($localname, $value) {
1893          //namespace URI for xmlns attribute is: http://www.w3.org/2000/xmlns/
1894          $this->setAttributeNS(DOMIT_XMLNS_NAMESPACE, ('xmlns:' . $localname), $value);
1895  
1896          //add to local namespaceURI map
1897          $this->namespaceURIMap[$value] = $localname;
1898      } //declareNamespace
1899  
1900      /**
1901      * Creates a default xmlns declaration at the current element
1902      * @param array An array of namespace declarations in the scope of the current element
1903      */
1904  	function declareDefaultNamespace($value) {
1905          //namespace URI for xmlns attribute is: http://www.w3.org/2000/xmlns/
1906          $this->setAttributeNS(DOMIT_XMLNS_NAMESPACE, 'xmlns', $value);
1907  
1908          //add to local namespaceURI map
1909          $this->namespaceURIMap[$value] = 'xmlns';
1910      } //declareDefaultNamespace
1911  
1912      /**
1913      * Returns an array of namespace declarations in the scope of the current element
1914      * @return array An array of namespace declarations in the scope of the current element
1915      */
1916      function &getNamespaceDeclarationsInScope() {
1917          $nsMap = array();
1918  
1919          return $this->_getNameSpaceDeclarationsInScope($nsMap);
1920      } //getNamespacesInScope
1921  
1922      /**
1923      * Returns an array of namespace declarations in the scope of the current element
1924      * @return array An array of namespace declarations in the scope of the current element
1925      */
1926      function &_getNamespaceDeclarationsInScope(&$nsMap) {
1927          //grab local xmlns declarations if not already present
1928          foreach ($this->namespaceURIMap as $key => $value) {
1929              if (!isset($nsMap[$key])) {
1930                  $nsMap[$key] = $value;
1931              }
1932          }
1933  
1934          //move up the tree if not already at the top
1935          if ($this->parentNode->uid != $this->ownerDocument->uid) {
1936              $this->parentNode->_getNamespaceDeclarationsInScope($nsMap);
1937          }
1938  
1939          return $nsMap;
1940      } //_getNamespacesInScope
1941  
1942      /**
1943      * Returns the default xmlns declaration for the current element
1944      * @return string The default xmlns declaration for the current element
1945      */
1946  	function getDefaultNamespaceDeclaration() {
1947          if (in_array('xmlns', $this->namespaceURIMap)) {
1948              foreach ($this->namespaceURIMap as $key => $value) {
1949                  if ($value == 'xmlns') {
1950                      return $key;
1951                  }
1952              }
1953          }
1954          else if ($this->parentNode->uid != $this->ownerDocument->uid) {
1955              return $this->parentNode->getDefaultNamespaceDeclaration();
1956          }
1957          else {
1958              return '';
1959          }
1960      } //getDefaultNamespaceDeclaration
1961  
1962      /**
1963      * Copies all namespace declarations in scope to the namespace URI map of the current element
1964      */
1965  	function copyNamespaceDeclarationsLocally() {
1966          $nsMap = $this->getNamespaceDeclarationsInScope();
1967  
1968          //add xmlns declarations as attributes
1969          foreach ($nsMap as $key => $value) {
1970              if ($value == 'xmlns') {
1971                  $this->declareDefaultNamespace($key);
1972              }
1973              else {
1974                  $this->declareNamespace($value, $key);
1975              }
1976          }
1977      } //copyNamespaceDeclarationsLocally
1978  
1979      /**
1980      * Adds elements with the specified tag name to a NodeList collection
1981      * @param Object The NodeList collection
1982      * @param string The namespaceURI of matching elements
1983      * @param string The localName of matching elements
1984      */
1985  	function getNamedElementsNS(&$nodeList, $namespaceURI, $localName) {
1986          if ((($namespaceURI == $this->namespaceURI) || ($namespaceURI == '*')) &&
1987                  (($localName == $this->localName) || ($localName == '*')))    {
1988              $nodeList->appendNode($this);
1989          }
1990  
1991          $total = $this->childCount;
1992  
1993          for ($i = 0; $i < $total; $i++) {
1994              if ($this->childNodes[$i]->nodeType == DOMIT_ELEMENT_NODE) {
1995                  $this->childNodes[$i]->getNamedElementsNS($nodeList, $namespaceURI, $localName);
1996              }
1997          }
1998      } //getNamedElementsNS
1999  
2000      /**
2001      * Returns the concatented text of the current node and its children
2002      * @return string The concatented text of the current node and its children
2003      */
2004  	function getText() {
2005          $text = '';
2006          $numChildren = $this->childCount;
2007  
2008          for ($i = 0; $i < $numChildren; $i++) {
2009              $child =& $this->childNodes[$i];
2010              $text .= $child->getText();
2011          }
2012  
2013          return $text;
2014      } //getText
2015  
2016      /**
2017      * If a child text node exists, sets the nodeValue to $data. A child text node is created if none exists
2018      * @param string The text data of the node
2019      */
2020  	function setText($data) {
2021          switch ($this->childCount) {
2022              case 1:
2023                  if ($this->firstChild->nodeType == DOMIT_TEXT_NODE) {
2024                      $this->firstChild->setText($data);
2025                  }
2026                  break;
2027  
2028              case 0:
2029                  $childTextNode =& $this->ownerDocument->createTextNode($data);
2030                  $this->appendChild($childTextNode);
2031                  break;
2032  
2033              default:
2034                  //do nothing. Maybe throw error???
2035          }
2036      } //setText
2037  
2038      /**
2039      * Retrieves a NodeList of child elements with the specified tag name
2040      * @param string The matching element tag name
2041      * @return Object A NodeList of found elements
2042      */
2043      function &getElementsByTagName($tagName) {
2044          $nodeList = new DOMIT_NodeList();
2045          $this->getNamedElements($nodeList, $tagName);
2046  
2047          return $nodeList;
2048      } //getElementsByTagName
2049  
2050      /**
2051      * Retrieves a NodeList of child elements with the specified namespaceURI and localName
2052      * @param string The namespaceURI
2053      * @param string The localName
2054      * @return Object A NodeList of found elements
2055      */
2056      function &getElementsByTagNameNS($namespaceURI, $localName) {
2057          $nodeList = new DOMIT_NodeList();
2058          $this->getNamedElementsNS($nodeList, $namespaceURI, $localName);
2059  
2060          return $nodeList;
2061      } //getElementsByTagNameNS
2062  
2063      /**
2064      * Returns the attribute node whose ID is given by elementId.
2065      * @param string The id of the matching element
2066      * @param boolean True if XML spec is to be strictly adhered to (only attributes xml:id are considered valid)
2067      * @return Object The found attribute or null
2068      */
2069      function &_getElementByID($elementID, $isStrict) {
2070          if ($isStrict) {
2071              $myAttrNode =& $this->getAttributeNodeNS(DOMIT_XML_NAMESPACE, 'id');
2072              if (($myAttrNode != null)&& ($myAttrNode->getValue() == $elementID)) return $myAttrNode;
2073          }
2074          else {
2075              $myAttrNode =& $this->getAttributeNodeNS('', 'ID');
2076              if (($myAttrNode != null)&& ($myAttrNode->getValue() == $elementID)) return $myAttrNode;
2077  
2078              $myAttrNode =& $this->getAttributeNodeNS('', 'id');
2079              if (($myAttrNode != null)&& ($myAttrNode->getValue() == $elementID)) return $myAttrNode;
2080          }
2081  
2082          $total = $this->childCount;
2083  
2084          for ($i = 0; $i < $total; $i++) {
2085              if ($this->childNodes[$i]->nodeType == DOMIT_ELEMENT_NODE) {
2086                  $foundNode =& $this->childNodes[$i]->_getElementByID($elementID, $isStrict);
2087  
2088                  if ($foundNode != null) {
2089                      return $foundNode;
2090                  }
2091              }
2092          }
2093  
2094          $null = null;
2095          return $null;
2096      } //_getElementByID
2097  
2098      /**
2099      * Retrieves an element or DOMIT_NodeList of elements corresponding to an Xpath-like expression.
2100      * @param string The query pattern
2101      * @param int If a single node is to be returned (rather than the entire NodeList) the index of that node
2102      * @return mixed A NodeList or single node that matches the pattern
2103      */
2104      function &getElementsByPath($pattern, $nodeIndex = 0) {
2105          require_once (DOMIT_INCLUDE_PATH . 'xml_domit_getelementsbypath.php');
2106  
2107          $gebp = new DOMIT_GetElementsByPath();
2108          $myResponse =& $gebp->parsePattern($this, $pattern, $nodeIndex);
2109  
2110          return $myResponse;
2111      } //getElementsByPath
2112  
2113      /**
2114      * Retrieves an element or DOMIT_NodeList of elements corresponding to an Xpath-like attribute expression (NOT YET IMPLEMENTED!)
2115      * @param string The query pattern
2116      * @param int If a single node is to be returned (rather than the entire NodeList) the index of that node
2117      * @return mixed A NodeList or single node that matches the pattern
2118      */
2119      function &getElementsByAttributePath($pattern, $nodeIndex = 0) {
2120          require_once (DOMIT_INCLUDE_PATH . 'xml_domit_getelementsbypath.php');
2121  
2122          $gabp = new DOMIT_GetElementsByAttributePath();
2123          $myResponse =& $gabp->parsePattern($this, $pattern, $nodeIndex);
2124  
2125          return $myResponse;
2126      } //getElementsByAttributePath
2127  
2128      /**
2129      * Adds all child nodes of the specified nodeType to the NodeList
2130      * @param Object The NodeList collection
2131      * @param string The nodeType of matching nodes
2132      */
2133  	function getTypedNodes(&$nodeList, $type) {
2134          $numChildren = $this->childCount;
2135  
2136          for ($i = 0; $i < $numChildren; $i++) {
2137              $child =& $this->childNodes[$i];
2138  
2139              if ($child->nodeType == $type) {
2140                  $nodeList->appendNode($child);
2141              }
2142  
2143              if ($child->hasChildNodes()) {
2144                  $child->getTypedNodes($nodeList, $type);
2145              }
2146          }
2147      } //getTypedNodes
2148  
2149      /**
2150      * Adds all child nodes of the specified nodeValue to the NodeList
2151      * @param Object The NodeList collection
2152      * @param string The nodeValue of matching nodes
2153      */
2154  	function getValuedNodes(&$nodeList, $value) {
2155          $numChildren = $this->childCount;
2156  
2157          for ($i = 0; $i < $numChildren; $i++) {
2158              $child =& $this->childNodes[$i];
2159  
2160              if ($child->nodeValue == $value) {
2161                  $nodeList->appendNode($child);
2162              }
2163  
2164              if ($child->hasChildNodes()) {
2165                  $child->getValuedNodes($nodeList, $value);
2166              }
2167          }
2168      } //getValuedNodes
2169  
2170      /**
2171      * Gets the value of the specified attribute, if it exists
2172      * @param string The attribute name
2173      * @return string The attribute value
2174      */
2175  	function getAttribute($name) {
2176          $returnNode =& $this->attributes->getNamedItem($name);
2177  
2178          if ($returnNode == null) {
2179              return '';
2180          }
2181          else {
2182              return $returnNode->getValue();
2183          }
2184      } //getAttribute
2185  
2186      /**
2187      * Gets the value of the attribute with the specified namespaceURI and localName, if it exists
2188      * @param string The namespaceURI
2189      * @param string The localName
2190      * @return string The attribute value
2191      */
2192  	function getAttributeNS($namespaceURI, $localName) {
2193          $returnNode =& $this->attributes->getNamedItemNS($namespaceURI, $localName);
2194  
2195          if ($returnNode == null) {
2196              return '';
2197          }
2198          else {
2199              return $returnNode->getValue();
2200          }
2201      } //getAttributeNS
2202  
2203      /**
2204      * Sets the value of the specified attribute; creates a new attribute if one doesn't exist
2205      * @param string The attribute name
2206      * @param string The desired attribute value
2207      */
2208  	function setAttribute($name, $value) {
2209          $returnNode =& $this->attributes->getNamedItem($name);
2210  
2211          if ($returnNode == null) {
2212              $newAttr = new DOMIT_Attr($name);
2213              $newAttr->setValue($value);
2214              $this->attributes->setNamedItem($newAttr);
2215          }
2216          else {
2217              $returnNode->setValue($value);
2218          }
2219      } //setAttribute
2220  
2221      /**
2222      * Sets the value of the specified attribute; creates a new attribute if one doesn't exist
2223      * @param string The attribute namespaceURI
2224      * @param string The attribute qualifiedName
2225      * @param string The desired attribute value
2226      */
2227  	function setAttributeNS($namespaceURI, $qualifiedName, $value) {
2228          //get localName
2229          $colonIndex = strpos($qualifiedName, ":");
2230  
2231          if ($colonIndex !== false) {
2232              $localName = substr($qualifiedName, ($colonIndex + 1));
2233          }
2234          else {
2235              $localName = $qualifiedName;
2236          }
2237  
2238          $returnNode =& $this->attributes->getNamedItemNS($namespaceURI, $localName);
2239  
2240          if ($returnNode == null) {
2241              //create this manually in case element has no ownerDocument to reference
2242              $newAttr = new DOMIT_Attr($qualifiedName);
2243              $newAttr->prefix = substr($qualifiedName, 0, $colonIndex);
2244              $newAttr->localName = $localName;
2245              $newAttr->namespaceURI = $namespaceURI;
2246  
2247              $newAttr->setValue($value);
2248              $this->attributes->setNamedItemNS($newAttr);
2249              $newAttr->ownerElement =& $this;
2250          }
2251          else {
2252              $returnNode->setValue($value);
2253          }
2254      } //setAttributeNS
2255  
2256      /**
2257      * Removes the specified attribute
2258      * @param string The name of the attribute to be removed
2259      */
2260  	function removeAttribute($name) {
2261          $returnNode =& $this->attributes->removeNamedItem($name);
2262      } //removeAttribute
2263  
2264      /**
2265      * Removes the specified attribute
2266      * @param string The namespaceURI of the attribute to be removed
2267      * @param string The localName of the attribute to be removed
2268      */
2269  	function removeAttributeNS($namespaceURI, $localName) {
2270          $returnNode =& $this->attributes->removeNamedItemNS($namespaceURI, $localName);
2271          unset($returnNode->ownerElement);
2272          $returnNode->ownerElement = null;
2273      } //removeAttributeNS
2274  
2275      /**
2276      * Determines whether an attribute with the specified name exists
2277      * @param string The name of the attribute
2278      * @return boolean True if the attribute exists
2279      */
2280  	function hasAttribute($name) {
2281          $returnNode =& $this->attributes->getNamedItem($name);
2282  
2283          return ($returnNode != null);
2284      } //hasAttribute
2285  
2286      /**
2287      * Determines whether an attribute with the specified namespaceURI and localName exists
2288      * @param string The namespaceURI of the attribute
2289      * @param string The localName of the attribute
2290      * @return boolean True if the attribute exists
2291      */
2292  	function hasAttributeNS($namespaceURI, $localName) {
2293          $returnNode =& $this->attributes->getNamedItemNS($namespaceURI, $localName);
2294  
2295          return ($returnNode != null);
2296      } //hasAttributeNS
2297  
2298      /**
2299      * Determines whether the element has any atributes
2300      * @return boolean True if the element has any atributes
2301      */
2302  	function hasAttributes() {
2303          return ($this->attributes->getLength() > 0);
2304      } //hasChildNodes
2305  
2306      /**
2307      * Gets a reference to the specified attribute node
2308      * @param string The attribute name
2309      * @return Object A reference to the found node, or null
2310      */
2311      function &getAttributeNode($name) {
2312          $returnNode =& $this->attributes->getNamedItem($name);
2313          return $returnNode;
2314      } //getAttributeNode
2315  
2316      /**
2317      * Gets a reference to the specified attribute node
2318      * @param string The attribute namespaceURI
2319      * @param string The attribute localName
2320      * @return Object A reference to the found node, or null
2321      */
2322      function &getAttributeNodeNS($namespaceURI, $localName) {
2323          $returnNode =& $this->attributes->getNamedItemNS($namespaceURI, $localName);
2324          return $returnNode;
2325      } //getAttributeNodeNS
2326  
2327      /**
2328      * Adds an attribute node to the current element
2329      * @param Object The attribute node to be added
2330      * @return Object A reference to the newly added node
2331      */
2332      function &setAttributeNode(&$newAttr) {
2333          $returnNode =& $this->attributes->setNamedItem($newAttr);
2334          return $returnNode;
2335      } //setAttributeNode
2336  
2337      /**
2338      * Adds an attribute node to the current element (namespace aware)
2339      * @param Object The attribute node to be added
2340      * @return Object A reference to the newly added node
2341      */
2342      function &setAttributeNodeNS(&$newAttr) {
2343          $returnNode =& $this->attributes->setNamedItemNS($newAttr);
2344          $newAttr->ownerElement =& $this;
2345          return $returnNode;
2346      } //setAttributeNodeNS
2347  
2348      /**
2349      * Removes an attribute node from the current element
2350      * @param Object The attribute node to be removed
2351      * @return Object A reference to the removed node
2352      */
2353      function &removeAttributeNode(&$oldAttr) {
2354          $attrName = $oldAttr->getName();
2355          $returnNode =& $this->attributes->removeNamedItem($attrName);
2356  
2357          if ($returnNode == null) {
2358              DOMIT_DOMException::raiseException(DOMIT_NOT_FOUND_ERR,
2359                  'Target attribute not found.');
2360          }
2361          else {
2362              return $returnNode;
2363          }
2364      } //removeAttributeNode
2365  
2366      /**
2367      * Collapses adjacent text nodes in entire element subtree
2368      */
2369  	function normalize() {
2370          if ($this->hasChildNodes()) {
2371              $currNode =& $this->childNodes[0];
2372  
2373              while ($currNode->nextSibling != null) {
2374                  $nextNode =& $currNode->nextSibling;
2375  
2376                  if (($currNode->nodeType == DOMIT_TEXT_NODE) &&
2377                          ($nextNode->nodeType == DOMIT_TEXT_NODE)) {
2378  
2379                      $currNode->nodeValue .= $nextNode->nodeValue;
2380                      $this->removeChild($nextNode);
2381                  }
2382                  else {
2383                      $currNode->normalize();
2384                  }
2385  
2386                  if ($currNode->nextSibling != null) {
2387                      $currNode =& $currNode->nextSibling;
2388                  }
2389              }
2390          }
2391      } //normalize
2392  
2393      /**
2394      * Generates an array representation of the node and its children
2395      * @return Array A representation of the node and its children
2396      */
2397  	function toArray() {
2398          $arReturn = array($this->nodeName => array("attributes" => $this->attributes->toArray()));
2399          $total = $this->childCount;
2400  
2401          for ($i = 0; $i < $total; $i++) {
2402              $arReturn[$this->nodeName][$i] = $this->childNodes[$i]->toArray();
2403          }
2404  
2405          return $arReturn;
2406      } //toArray
2407  
2408      /**
2409      * Copies a node and/or its children
2410      * @param boolean True if all child nodes are also to be cloned
2411      * @return Object A copy of the node and/or its children
2412      */
2413      function &cloneNode($deep = false) {
2414          $className = get_class($this);
2415          $clone = new $className($this->nodeName);
2416  
2417          $clone->attributes =& $this->attributes->createClone($deep);
2418  
2419          if ($this->namespaceURI) {
2420              $clone->namespaceURI = $this->namespaceURI;
2421              $clone->localName = $this->localName;
2422          }
2423  
2424          if ($deep) {
2425              $total = $this->childCount;
2426  
2427              for ($i = 0; $i < $total; $i++) {
2428                  $currentChild =& $this->childNodes[$i];
2429                  $clone->appendChild($currentChild->cloneNode($deep));
2430              }
2431          }
2432  
2433          return $clone;
2434      } //cloneNode
2435  
2436      /**
2437      * Generates a string representation of the node and its children
2438      * @param boolean True if HTML readable output is desired
2439      * @param boolean True if illegal xml characters in text nodes and attributes should be converted to entities
2440      * @return string The string representation
2441      */
2442  	function toString($htmlSafe = false, $subEntities = false) {
2443          $result = '<' . $this->nodeName;
2444          $result .= $this->attributes->toString(false, $subEntities);
2445  
2446          if ($this->ownerDocument->isNamespaceAware) {
2447              foreach ($this->namespaceURIMap as $key => $value) {
2448                  $result    .= ' xmlns:' . $value . '="' . $key . '"';
2449              }
2450          }
2451  
2452          //get children
2453          $myNodes =& $this->childNodes;
2454          $total = count($myNodes);
2455  
2456          if ($total != 0) {
2457              $result .= '>';
2458  
2459              for ($i = 0; $i < $total; $i++) {
2460                  $child =& $myNodes[$i];
2461                  $result .= $child->toString(false, $subEntities);
2462              }
2463  
2464              $result .= '</' . $this->nodeName . '>';
2465          }
2466          else {
2467              if ($this->ownerDocument->doExpandEmptyElementTags) {
2468                  if (in_array($this->nodeName, $this->ownerDocument->expandEmptyElementExceptions)) {
2469                      $result .= ' />';
2470                  }
2471                  else {
2472                      $result .= '></' . $this->nodeName . '>';
2473                  }
2474              }
2475              else {
2476                  if (in_array($this->nodeName, $this->ownerDocument->expandEmptyElementExceptions)) {
2477                      $result .= '></' . $this->nodeName . '>';
2478                  }
2479                  else {
2480                      $result .= ' />';
2481                  }
2482              }
2483          }
2484  
2485          if ($htmlSafe) $result = $this->forHTML($result);
2486  
2487          return $result;
2488      } //toString
2489  } //DOMIT_Element
2490  
2491  /**
2492  * A parent class for Text and CDATA Section nodes
2493  *
2494  * @package domit-xmlparser
2495  * @subpackage domit-xmlparser-main
2496  * @author John Heinstein <johnkarl@nbnet.nb.ca>
2497  */
2498  class DOMIT_CharacterData extends DOMIT_Node {
2499      /**
2500      * Prevents direct instantiation of DOMIT_CharacterData class
2501      * @abstract
2502      */
2503  	function DOMIT_CharacterData() {
2504          DOMIT_DOMException::raiseException(DOMIT_ABSTRACT_CLASS_INSTANTIATION_ERR,
2505               'Cannot instantiate abstract class DOMIT_CharacterData');
2506      } //DOMIT_CharacterData
2507  
2508      /**
2509      * Gets the node value of the current text node
2510      * @return string The node value of the current text node
2511      */
2512  	function getData() {
2513          return $this->nodeValue;
2514      } //getData
2515  
2516      /**
2517      * Sets the text contained in the current node to $data.
2518      * @param string The text data of the node
2519      */
2520  	function setData($data) {
2521          $this->nodeValue = $data;
2522      } //setData
2523  
2524  
2525      /**
2526      * Gets the length of the text in the current node
2527      * @return int The length of the text in the current node
2528      */
2529  	function getLength() {
2530          return strlen($this->nodeValue);
2531      } //getLength
2532  
2533      /**
2534      * Gets a subset of the current node text
2535      * @param int The starting point of the substring
2536      * @param int The length of the substring
2537      * @return string The subset of the current node text
2538      */
2539  	function substringData($offset, $count) {
2540          $totalChars = $this->getLength();
2541  
2542          if (($offset < 0) || (($offset + $count) > $totalChars)) {
2543  
2544              DOMIT_DOMException::raiseException(DOMIT_INDEX_SIZE_ERR,
2545                  'Character Data index out of bounds.');
2546  
2547          }
2548          else {
2549              $data = $this->getData();
2550              return substr($data, $offset, $count);
2551          }
2552      } //substringData
2553  
2554      /**
2555      * Appends the specified text to the current node text
2556      * @param string The text to be appended
2557      */
2558  	function appendData($arg) {
2559          $this->setData($this->getData() . $arg);
2560      } //appendData
2561  
2562      /**
2563      * Inserts text at the sepecified offset
2564      * @param int The insertion point
2565      * @param string The text to be inserted
2566      */
2567  	function insertData($offset, $arg) {
2568          $totalChars = $this->getLength();
2569  
2570          if (($offset < 0) || ($offset > $totalChars)) {
2571  
2572              DOMIT_DOMException::raiseException(DOMIT_INDEX_SIZE_ERR,
2573                  'Character Data index out of bounds.');
2574  
2575          }
2576          else {
2577              $data = $this->getData();
2578              $pre = substr($data, 0, $offset);
2579              $post = substr($data, $offset);
2580  
2581              $this->setData(($pre . $arg . $post));
2582          }
2583      } //insertData
2584  
2585      /**
2586      * Deletes a subset of the current node text
2587      * @param int The starting point of the deletion
2588      * @param int The length of the deletion
2589      */
2590  	function deleteData($offset, $count) {
2591          $totalChars = $this->getLength();
2592  
2593          if (($offset < 0) || (($offset + $count) > $totalChars)) {
2594  
2595              DOMIT_DOMException::raiseException(DOMIT_INDEX_SIZE_ERR,
2596                  'Character Data index out of bounds.');
2597  
2598          }
2599          else {
2600              $data = $this->getData();
2601              $pre = substr($data, 0, $offset);
2602              $post = substr($data, ($offset + $count));
2603  
2604              $this->setData(($pre . $post));
2605          }
2606      } //substringData
2607  
2608      /**
2609      * Replaces a subset of the current node text with the specified text
2610      * @param int The starting point of the replacement
2611      * @param int The length of the replacement
2612      * @param string The replacement text
2613      */
2614  	function replaceData($offset, $count, $arg) {
2615          $totalChars = $this->getLength();
2616  
2617          if (($offset < 0) || (($offset + $count) > $totalChars)) {
2618  
2619              DOMIT_DOMException::raiseException(DOMIT_INDEX_SIZE_ERR,
2620                  'Character Data index out of bounds.');
2621  
2622          }
2623          else {
2624              $data = $this->getData();
2625              $pre = substr($data, 0, $offset);
2626              $post = substr($data, ($offset + $count));
2627  
2628              $this->setData(($pre . $arg . $post));
2629          }
2630      } //replaceData
2631  } //DOMIT_CharacterData
2632  
2633  /**
2634  * A class representing the DOM Text Node
2635  *
2636  * @package domit-xmlparser
2637  * @subpackage domit-xmlparser-main
2638  * @author John Heinstein <johnkarl@nbnet.nb.ca>
2639  */
2640  class DOMIT_TextNode extends DOMIT_CharacterData {
2641      /**
2642      * DOM Text Node constructor
2643      * @param string The text of the node
2644      */
2645  	function DOMIT_TextNode($data) {
2646          $this->_constructor();
2647          $this->nodeType = DOMIT_TEXT_NODE;
2648          $this->nodeName = '#text';
2649          $this->setText($data);
2650      } //DOMIT_TextNode
2651  
2652      /**
2653      * Returns the text contained in the current node
2654      * @return string The text of the current node
2655      */
2656  	function getText() {
2657          return $this->nodeValue;
2658      } //getText
2659  
2660      /**
2661      * Sets the text contained in the current node to $data.
2662      * @param string The text data of the node
2663      */
2664  	function setText($data) {
2665          $this->nodeValue = $data;
2666      } //setText
2667  
2668      /**
2669      * Splits a single node into multiple nodes, based on the specified offset
2670      * @param int The offset point for the split
2671      * @return Object The newly created text node
2672      */
2673      function &splitText($offset) {
2674          $totalChars = $this->getLength();
2675  
2676          if (($offset < 0) || ($offset > $totalChars)) {
2677  
2678              DOMIT_DOMException::raiseException(DOMIT_INDEX_SIZE_ERR,
2679                  'Character Data index out of bounds.');
2680  
2681          }
2682          else {
2683              $data = $this->getData();
2684              $pre = substr($data, 0, $offset);
2685              $post = substr($data, $offset);
2686  
2687              $this->setText($pre);
2688  
2689              //create new text node
2690              $className = get_class($this);
2691              $newTextNode = new $className($post);
2692              $newTextNode->ownerDocument =& $this->ownerDocument;
2693  
2694              if ($this->parentNode->lastChild->uid == $this->uid) {
2695                  $this->parentNode->appendChild($newTextNode);
2696              }
2697              else {
2698                  $this->parentNode->insertBefore($newTextNode, $this);
2699              }
2700  
2701              return $newTextNode;
2702          }
2703      } //splitText
2704  
2705      /**
2706      * Generates an array representation of the node and its children
2707      * @return Array A representation of the node and its children
2708      */
2709  	function toArray() {
2710          return $this->toString();
2711      } //toArray
2712  
2713      /**
2714      * Copies a node and/or its children
2715      * @param boolean True if all child nodes are also to be cloned
2716      * @return Object A copy of the node and/or its children
2717      */
2718      function &cloneNode($deep = false) {
2719          $className = get_class($this);
2720          $clone = new $className($this->nodeValue);
2721  
2722          return $clone;
2723      } //cloneNode
2724  
2725      /**
2726      * Generates a string representation of the node and its children
2727      * @param boolean True if HTML readable output is desired
2728      * @param boolean True if illegal xml characters should be converted to entities
2729      * @return string The string representation
2730      */
2731  	function toString($htmlSafe = false, $subEntities = false) {
2732          require_once (DOMIT_INCLUDE_PATH . 'xml_domit_utilities.php');
2733          global $DOMIT_defined_entities_flip;
2734  
2735          $result = $subEntities ? DOMIT_Utilities::convertEntities($this->nodeValue,
2736                              $DOMIT_defined_entities_flip) : $this->nodeValue;
2737  
2738          if ($htmlSafe) $result = $this->forHTML($result);
2739  
2740          return $result;
2741      } //toString
2742  } //DOMIT_TextNode
2743  
2744  /**
2745  * A class representing the DOM CDATA Section
2746  *
2747  * @package domit-xmlparser
2748  * @subpackage domit-xmlparser-main
2749  * @author John Heinstein <johnkarl@nbnet.nb.ca>
2750  */
2751  class DOMIT_CDATASection extends DOMIT_TextNode {
2752      /**
2753      * DOM CDATA Section node constructor
2754      * @param string The text of the node
2755      */
2756  	function DOMIT_CDATASection($data) {
2757          $this->_constructor();
2758          $this->nodeType = DOMIT_CDATA_SECTION_NODE;
2759          $this->nodeName = '#cdata-section';
2760          $this->setText($data);
2761      } //DOMIT_CDATASection
2762  
2763      /**
2764      * Generates a string representation of the node and its children
2765      * @param boolean True if HTML readable output is desired
2766      * @param boolean True if illegal xml characters should be converted to entities
2767      * @return string The string representation
2768      */
2769  	function toString($htmlSafe = false, $subEntities = false) {
2770          $result = '<![CDATA[';
2771          $result .= $subEntities ? str_replace("]]>", "]]&gt;", $this->nodeValue) :
2772                                   $this->nodeValue;
2773          $result .= ']]>';
2774  
2775          if ($htmlSafe) $result = $this->forHTML($result);
2776  
2777          return $result;
2778      } //toString
2779  } //DOMIT_CDATASection
2780  
2781  /**
2782  * A class representing the Attr node
2783  *
2784  * @package domit-xmlparser
2785  * @subpackage domit-xmlparser-main
2786  * @author John Heinstein <johnkarl@nbnet.nb.ca>
2787  */
2788  class DOMIT_Attr extends DOMIT_Node {
2789      /** @var boolean True if the attribute has been modified since parsing (NOT YET IMPLEMENTED!) */
2790      var $specified = false;
2791      /** @var Object A reference to the element to which the attribute is assigned */
2792      var $ownerElement = null;
2793  
2794      /**
2795      * DOM Attr node constructor
2796      * @param string The name of the attribute
2797      */
2798  	function DOMIT_Attr($name) {
2799          $this->_constructor();
2800          $this->nodeType = DOMIT_ATTRIBUTE_NODE;
2801          $this->nodeName =$name;
2802      } //DOMIT_Attr
2803  
2804      /**
2805      * Returns the name of the attribute
2806      * @return string The name of the attribute
2807      */
2808  	function getName() {
2809          return $this->nodeName;
2810      } //getName
2811  
2812      /**
2813      * Indicates whether an attribute has been modified since parsing
2814      * @return boolean True if the node has been modified
2815      */
2816  	function getSpecified() {
2817          return $this->specified;
2818      } //getSpecified
2819  
2820      /**
2821      * Returns the value of the attribute
2822      * @return string The value of the attribute
2823      */
2824  	function getValue() {
2825          return $this->nodeValue;
2826      } //getValue
2827  
2828      /**
2829      * Sets the value of the attribute
2830      * @param string The value of the attribute
2831      */
2832  	function setValue($value) {
2833          $this->nodeValue = $value;
2834      } //setValue
2835  
2836      /**
2837      * Returns the text contained in the current node
2838      * @return string The text of the current node
2839      */
2840  	function getText() {
2841          return $this->nodeValue;
2842      } //getText
2843  
2844      /**
2845      * Sets the text contained in the current node to $data.
2846      * @param string The text data of the node
2847      */
2848  	function setText($data) {
2849          $this->nodeValue = $data;
2850      } //setText
2851  
2852      /**
2853      * Copies a node and/or its children
2854      * @param boolean True if all child nodes are also to be cloned
2855      * @return Object A copy of the node and/or its children
2856      */
2857      function &cloneNode($deep = false) {
2858          $className = get_class($this);
2859          $clone = new $className($this->nodeName);
2860          $clone->nodeValue = $this->nodeValue;
2861  
2862          if ($this->namespaceURI) {
2863              $clone->namespaceURI = $this->namespaceURI;
2864              $clone->localName = $this->localName;
2865          }
2866  
2867          return $clone;
2868      } //cloneNode
2869  
2870      /**
2871      * Generates a string representation of the node and its children
2872      * @param boolean True if HTML readable output is desired
2873      * @param boolean True if HTML entities should be substituted
2874      * @return string The string representation
2875      */
2876  	function toString($htmlSafe = false, $subEntities = false) {
2877          require_once (DOMIT_INCLUDE_PATH . 'xml_domit_utilities.php');
2878          global $DOMIT_defined_entities_flip;
2879  
2880          $result = ' ' . $this->nodeName . '="';
2881          $result .= $subEntities ? DOMIT_Utilities::convertEntities($this->nodeValue,
2882                              $DOMIT_defined_entities_flip) : $this->nodeValue;
2883          $result .= '"';
2884  
2885          if ($htmlSafe) $result = $this->forHTML($result);
2886  
2887          return $result;
2888      } //toString
2889  } //DOMIT_Attr
2890  
2891  /**
2892  * A class representing the DOM Document Fragment node
2893  *
2894  * @package domit-xmlparser
2895  * @subpackage domit-xmlparser-main
2896  * @author John Heinstein <johnkarl@nbnet.nb.ca>
2897  */
2898  class DOMIT_DocumentFragment extends DOMIT_ChildNodes_Interface {
2899      /**
2900      * DOM Document Fragment node constructor
2901      */
2902  	function DOMIT_DocumentFragment() {
2903          $this->_constructor();
2904          $this->nodeType = DOMIT_DOCUMENT_FRAGMENT_NODE;
2905          $this->nodeName ='#document-fragment';
2906          $this->nodeValue = null;
2907          $this->childNodes = array();
2908      } //DOMIT_DocumentFragment
2909  
2910      /**
2911      * Generates an array representation of the node and its children
2912      * @return Array A representation of the node and its children
2913      */
2914  	function toArray() {
2915          $arReturn = array();
2916          $total = $this->childCount;
2917  
2918          for ($i = 0; $i < $total; $i++) {
2919              $arReturn[$i] = $this->childNodes[$i]->toArray();
2920          }
2921  
2922          return $arReturn;
2923      } //toArray
2924  
2925      /**
2926      * Copies a node and/or its children
2927      * @param boolean True if all child nodes are also to be cloned
2928      * @return Object A copy of the node and/or its children
2929      */
2930      function &cloneNode($deep = false) {
2931          $className = get_class($this);
2932          $clone = new $className();
2933  
2934          if ($deep) {
2935              $total = $this->childCount;
2936  
2937              for ($i = 0; $i < $total; $i++) {
2938                  $currentChild =& $this->childNodes[$i];
2939                  $clone->appendChild($currentChild->cloneNode($deep));
2940              }
2941          }
2942  
2943          return $clone;
2944      } //cloneNode
2945  
2946      /**
2947      * Generates a string representation of the node and its children
2948      * @param boolean True if HTML readable output is desired
2949      * @return string The string representation
2950      */
2951  	function toString($htmlSafe = false, $subEntities = false) {
2952          //get children
2953          $result = '';
2954          $myNodes =& $this->childNodes;
2955          $total = count($myNodes);
2956  
2957          if ($total != 0) {
2958              for ($i = 0; $i < $total; $i++) {
2959                  $child =& $myNodes[$i];
2960                  $result .= $child->toString(false, $subEntities);
2961              }
2962          }
2963  
2964          if ($htmlSafe) $result = $this->forHTML($result);
2965  
2966          return $result;
2967      } //toString
2968  } //DOMIT_DocumentFragment
2969  
2970  /**
2971  * A class representing the DOM Comment node
2972  *
2973  * @package domit-xmlparser
2974  * @subpackage domit-xmlparser-main
2975  * @author John Heinstein <johnkarl@nbnet.nb.ca>
2976  */
2977  class DOMIT_Comment extends DOMIT_CharacterData {
2978      /**
2979      * DOM Comment node constructor
2980      * @param string The
2981      */
2982  	function DOMIT_Comment($nodeValue) {
2983          $this->_constructor();
2984          $this->nodeType = DOMIT_COMMENT_NODE;
2985          $this->nodeName = '#comment';
2986          $this->nodeValue = $nodeValue;
2987      } //DOMIT_Comment
2988  
2989      /**
2990      * Returns the text contained in the current node
2991      * @return string The text of the current node
2992      */
2993  	function getText() {
2994          return $this->nodeValue;
2995      } //getText
2996  
2997      /**
2998      * Sets the text contained in the current node to $data.
2999      * @param string The text data of the node
3000      */
3001  	function setText($data) {
3002          $this->nodeValue = $data;
3003      } //setText
3004  
3005      /**
3006      * Generates an array representation of the node and its children
3007      * @return Array A representation of the node and its children
3008      */
3009  	function toArray() {
3010          return $this->toString();
3011      } //toArray
3012  
3013      /**
3014      * Copies a node and/or its children
3015      * @param boolean True if all child nodes are also to be cloned
3016      * @return Object A copy of the node and/or its children
3017      */
3018      function &cloneNode($deep = false) {
3019          $className = get_class($this);
3020          $clone = new $className($this->nodeValue);
3021  
3022          return $clone;
3023      } //cloneNode
3024  
3025      /**
3026      * Generates a string representation of the node and its children
3027      * @param boolean True if HTML readable output is desired
3028      * @return string The string representation
3029      */
3030  	function toString($htmlSafe = false) {
3031          $result = '<!--' . $this->nodeValue . '-->';
3032  
3033          if ($htmlSafe) $result = $this->forHTML($result);
3034  
3035          return $result;
3036      } //toString
3037  } //DOMIT_Comment
3038  
3039  /**
3040  * A class representing the DOM Processing Instruction node
3041  *
3042  * @package domit-xmlparser
3043  * @subpackage domit-xmlparser-main
3044  * @author John Heinstein <johnkarl@nbnet.nb.ca>
3045  */
3046  class DOMIT_ProcessingInstruction extends DOMIT_Node {
3047      /**
3048      * DOM Processing Instruction node constructor
3049      * @param string The
3050      */
3051  	function DOMIT_ProcessingInstruction($target, $data) {
3052          $this->_constructor();
3053          $this->nodeType = DOMIT_PROCESSING_INSTRUCTION_NODE;
3054          $this->nodeName = $target;
3055          $this->nodeValue = $data;
3056      } //DOMIT_ProcessingInstruction
3057  
3058      /**
3059      * Returns the processing instruction target
3060      * @return string The processing instruction target
3061      */
3062  	function getTarget() {
3063          return $this->nodeName;
3064      } //getTarget
3065  
3066      /**
3067      * Returns the processing instruction data
3068      * @return string The processing instruction data
3069      */
3070  	function getData() {
3071          return $this->nodeValue;
3072      } //getData
3073  
3074      /**
3075      * Returns the text contained in the current node
3076      * @return string The text of the current node
3077      */
3078  	function getText() {
3079          return ($this->nodeName . ' ' . $this->nodeValue);
3080      } //getText
3081  
3082      /**
3083      * Generates an array representation of the node and its children
3084      * @return Array A representation of the node and its children
3085      */
3086  	function toArray() {
3087          return $this->toString();
3088      } //toArray
3089  
3090      /**
3091      * Copies a node and/or its children
3092      * @param boolean True if all child nodes are also to be cloned
3093      * @return Object A copy of the node and/or its children
3094      */
3095      function &cloneNode($deep = false) {
3096          $className = get_class($this);
3097          $clone = new $className($this->nodeName, $this->nodeValue);
3098  
3099          return $clone;
3100      } //cloneNode
3101  
3102      /**
3103      * Generates a string representation of the node and its children
3104      * @param boolean True if HTML readable output is desired
3105      * @return string The string representation
3106      */
3107  	function toString($htmlSafe = false) {
3108          $result = '<' . '?' . $this->nodeName . ' ' . $this->nodeValue . '?' . '>';
3109  
3110          if ($htmlSafe) $result = $this->forHTML($result);
3111  
3112          return $result;
3113      } //toString
3114  } //DOMIT_ProcessingInstruction
3115  
3116  /**
3117  * A class representing the DOM Document Type node
3118  *
3119  * @package domit-xmlparser
3120  * @subpackage domit-xmlparser-main
3121  * @author John Heinstein <johnkarl@nbnet.nb.ca>
3122  */
3123  class DOMIT_DocumentType extends DOMIT_Node {
3124      /** @var string The doctype name */
3125      var $name;
3126      /** @var Object True if the entity has been modified since parsing (NOT YET IMPLEMENTED!) */
3127      var $entities;
3128      /** @var Object A NodeList of notation nodes (NOT YET IMPLEMENTED!) */
3129      var $notations;
3130      /** @var Object A NodeList of elements (NOT YET IMPLEMENTED!) */
3131      var $elements;
3132      /** @var string The full text of the doctype */
3133      var $text;
3134      /** @var string The public identifier of the external subset */
3135      var $publicID;
3136      /** @var string The system identifier of the external subset */
3137      var $systemID;
3138      /** @var string The full text of internal subset */
3139      var $internalSubset;
3140  
3141      /**
3142      * DOM Document Type node constructor
3143      * @param string The
3144      */
3145  	function DOMIT_DocumentType($name, $text) {
3146          $this->_constructor();
3147          $this->nodeType = DOMIT_DOCUMENT_TYPE_NODE;
3148          $this->nodeName = $name;
3149          $this->name = $name;
3150          $this->entities = null; //implement later
3151          $this->notations = null; //implement later
3152          $this->elements = null; //implement later
3153          $this->text = $text;
3154      } //DOMIT_DocumentType
3155  
3156      /**
3157      * Returns the text contained in the current node
3158      * @return string The text of the current node
3159      */
3160  	function getText() {
3161          return $this->text;
3162      } //getText
3163  
3164      /**
3165      * Returns the name of the doctype node
3166      * @return string The name of the doctype node
3167      */
3168  	function getName() {
3169          return $this->name;
3170      } //getName
3171  
3172      /**
3173      * Generates an array representation of the node and its children
3174      * @return Array A representation of the node and its children
3175      */
3176  	function toArray() {
3177          return $this->toString();
3178      } //toArray
3179  
3180      /**
3181      * Copies a node and/or its children
3182      * @param boolean True if all child nodes are also to be cloned
3183      * @return Object A copy of the node and/or its children
3184      */
3185      function &cloneNode($deep = false) {
3186          $className = get_class($this);
3187          $clone = new $className($this->nodeName, $this->text);
3188  
3189          return $clone;
3190      } //cloneNode
3191  
3192      /**
3193      * Generates a string representation of the node and its children
3194      * @param boolean True if HTML readable output is desired
3195      * @return string The string representation
3196      */
3197  	function toString($htmlSafe = false) {
3198          $result = $this->text;
3199  
3200          if ($htmlSafe) $result = $this->forHTML($result);
3201  
3202          return $result;
3203      } //toString
3204  } //DOMIT_DocumentType
3205  
3206  
3207  /**
3208  * A class representing the DOM Notation node (NOT YET IMPLEMENTED!)
3209  *
3210  * @package domit-xmlparser
3211  * @subpackage domit-xmlparser-main
3212  * @author John Heinstein <johnkarl@nbnet.nb.ca>
3213  */
3214  class DOMIT_Notation extends DOMIT_Node {
3215      /**
3216      * DOM Notation node constructor (NOT YET IMPLEMENTED!)
3217      */
3218  	function DOMIT_Notation() {
3219          DOMIT_DOMException::raiseException(DOMIT_NOT_SUPPORTED_ERR,
3220               'Cannot instantiate DOMIT_Notation class. Notation nodes not yet supported.');
3221      } //DOMIT_Notation
3222  } //DOMIT_Notation
3223  
3224  /**
3225  * Manages the generation of a DOMIT! document from SAX events
3226  *
3227  * @package domit-xmlparser
3228  * @subpackage domit-xmlparser-main
3229  * @author John Heinstein <johnkarl@nbnet.nb.ca>
3230  */
3231  class DOMIT_Parser {
3232      /** @var Object A reference to the resulting xmldoc */
3233      var $xmlDoc = null;
3234      /** @var Object A reference to the current node in the parsing process */
3235      var $currentNode = null;
3236      /** @var Object A reference to the last child in the parsing process */
3237      var $lastChild = null;
3238      /** @var boolean True if currently parsing a CDATA Section */
3239      var $inCDATASection = false; //flag for Expat
3240      /** @var boolean True if currently parsing a Text node */
3241      var $inTextNode = false;
3242      /** @var boolean True is CDATA Section nodes are not to be converted into Text nodes */
3243      var $preserveCDATA;
3244      /** @var string A container for holding the currently parsed text data */
3245      var $parseContainer = '';
3246      /** @var string The current docutype text */
3247      var $parseItem = '';
3248      /** @var boolean True if waiting for an element to which to apply namespace declaration(s)  */
3249      var $waitingForElementToDeclareNamespaces = false;
3250      /** @var boolean True if waiting for an element to which to apply namespace declaration(s)  */
3251      var $tempNamespaceURIMap = array();
3252  
3253      /**
3254      * Parses xml text using Expat
3255      * @param Object A reference to the DOM document that the xml is to be parsed into
3256      * @param string The text to be parsed
3257      * @param boolean True if CDATA Section nodes are not to be converted into Text nodes
3258      * @return boolean True if the parsing is successful
3259      */
3260  	function parse (&$myXMLDoc, $xmlText, $preserveCDATA = true) {
3261          $this->xmlDoc =& $myXMLDoc;
3262          $this->lastChild =& $this->xmlDoc;
3263  
3264          $this->preserveCDATA = $preserveCDATA;
3265  
3266          //create instance of expat parser (should be included in php distro)
3267          if (version_compare(phpversion(), '5.0', '<=')) {
3268              if ($this->xmlDoc->isNamespaceAware) {
3269                  $parser = xml_parser_create_ns('');
3270              }
3271              else {
3272                  $parser = xml_parser_create('');
3273              }
3274          }
3275          else {
3276              if ($this->xmlDoc->isNamespaceAware) {
3277                  $parser = xml_parser_create_ns();
3278              }
3279              else {
3280                  $parser = xml_parser_create();
3281              }
3282          }
3283  
3284          //set handlers for SAX events
3285          xml_set_object($parser, $this);
3286          xml_set_character_data_handler($parser, 'dataElement');
3287          xml_set_default_handler($parser, 'defaultDataElement');
3288          xml_set_notation_decl_handler($parser, 'notationElement');
3289          xml_set_processing_instruction_handler($parser, 'processingInstructionElement');
3290          xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
3291  
3292          if (!$this->xmlDoc->preserveWhitespace) {
3293              xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
3294          }
3295          else {
3296              xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
3297          }
3298  
3299          if ($this->xmlDoc->isNamespaceAware) {
3300              xml_set_start_namespace_decl_handler($parser, 'startNamespaceDeclaration');
3301              xml_set_end_namespace_decl_handler($parser, 'endNamespaceDeclaration');
3302              xml_set_element_handler($parser, 'startElementNS', 'endElement');
3303              $this->xmlDoc->namespaceURIMap[DOMIT_XML_NAMESPACE] = 'xml';
3304          }
3305          else {
3306              xml_set_element_handler($parser, 'startElement', 'endElement');
3307          }
3308  
3309          //parse out whitespace -  (XML_OPTION_SKIP_WHITE = 1 does not
3310          //seem to work consistently across versions of PHP and Expat
3311          if (!$this->xmlDoc->preserveWhitespace) {
3312              $xmlText = eregi_replace('>' . "[[:space:]]+" . '<' , '><', $xmlText);
3313          }
3314  
3315          $success = xml_parse($parser, $xmlText);
3316  
3317          $this->xmlDoc->errorCode = xml_get_error_code($parser);
3318          $this->xmlDoc->errorString = xml_error_string($this->xmlDoc->errorCode);
3319  
3320          xml_parser_free($parser);
3321  
3322          return $success;
3323      } //parse
3324  
3325      /**
3326      * Parses xml text using SAXY
3327      * @param Object A reference to the DOM document that the xml is to be parsed into
3328      * @param string The text to be parsed
3329      * @param boolean True if CDATA Section nodes are not to be converted into Text nodes
3330      * @return boolean True if the parsing is successful
3331      */
3332  	function parseSAXY(&$myXMLDoc, $xmlText, $preserveCDATA = true, $definedEntities) {
3333          require_once (DOMIT_INCLUDE_PATH . 'xml_saxy_parser.php');
3334  
3335          $this->xmlDoc =& $myXMLDoc;
3336          $this->lastChild =& $this->xmlDoc;
3337  
3338          //create instance of SAXY parser
3339          $parser = new SAXY_Parser();
3340          $parser->appendEntityTranslationTable($definedEntities);
3341  
3342          //not yet implemented in SAXY!!!
3343          $parser->preserveWhitespace = $this->xmlDoc->preserveWhitespace;
3344  
3345          if ($this->xmlDoc->isNamespaceAware) {
3346              $parser->setNamespaceAwareness(true);
3347              $parser->xml_set_start_namespace_decl_handler(array(&$this, 'startNamespaceDeclaration'));
3348              $parser->xml_set_end_namespace_decl_handler(array(&$this, 'endNamespaceDeclaration'));
3349              $parser->xml_set_element_handler(array(&$this, 'startElementNS'), array(&$this, 'endElement'));
3350              $this->xmlDoc->namespaceURIMap[DOMIT_XML_NAMESPACE] = 'xml';
3351          }
3352          else {
3353              $parser->xml_set_element_handler(array(&$this, 'startElement'), array(&$this, 'endElement'));
3354          }
3355  
3356          $parser->xml_set_character_data_handler(array(&$this, 'dataElement'));
3357          $parser->xml_set_doctype_handler(array(&$this, 'doctypeElement'));
3358          $parser->xml_set_comment_handler(array(&$this, 'commentElement'));
3359          $parser->xml_set_processing_instruction_handler(array(&$this, 'processingInstructionElement'));
3360  
3361          if ($preserveCDATA) {
3362              $parser->xml_set_cdata_section_handler(array(&$this, 'cdataElement'));
3363          }
3364  
3365          $success = $parser->parse($xmlText);
3366  
3367          $this->xmlDoc->errorCode = $parser->xml_get_error_code();
3368          $this->xmlDoc->errorString = $parser->xml_error_string($this->xmlDoc->errorCode);
3369  
3370          return $success;
3371      } //parseSAXY
3372  
3373      /**
3374      * Generates and appends a new text node from the parseContainer text
3375      */
3376  	function dumpTextNode() {
3377          $currentNode =& $this->xmlDoc->createTextNode($this->parseContainer);
3378          $this->lastChild->appendChild($currentNode);
3379          $this->inTextNode = false;
3380          $this->parseContainer = '';
3381      } //dumpTextNode
3382  
3383      /**
3384      * Catches a start element event and processes the data
3385      * @param Object A reference to the current SAX parser
3386      * @param string The tag name of the current element
3387      * @param Array An array of the element attributes
3388      */
3389  	function startElement(&$parser, $name, $attrs) {
3390          if ($this->inTextNode) {
3391              $this->dumpTextNode();
3392          }
3393  
3394          $currentNode =& $this->xmlDoc->createElement($name);
3395          $this->lastChild->appendChild($currentNode);
3396  
3397          reset ($attrs);
3398  
3399          while (list($key, $value) = each ($attrs)) {
3400              $currentNode->setAttribute($key, $value);
3401          }
3402  
3403          $this->lastChild =& $currentNode;
3404      } //startElement
3405  
3406      /**
3407      * Catches a start element event and processes the data
3408      * @param Object A reference to the current SAX parser
3409      * @param string The tag name of the current element
3410      * @param Array An array of the element attributes
3411      */
3412  	function startElementNS(&$parser, $name, $attrs) {
3413          if ($this->inTextNode) {
3414             $this->dumpTextNode();
3415           }
3416  
3417          $colonIndex = strrpos($name, ":");
3418  
3419          if ($colonIndex !== false) {
3420              //force to lower case because Expat for some reason forces to upper case
3421              $namespaceURI = strtolower(substr($name, 0, $colonIndex));
3422              $prefix = $this->xmlDoc->namespaceURIMap[$namespaceURI];
3423  
3424              if ($prefix != '') {
3425                  $qualifiedName = $prefix . ":" . substr($name, ($colonIndex + 1));
3426              }
3427              else {
3428                  $qualifiedName = substr($name, ($colonIndex + 1));
3429              }
3430          }
3431          else {
3432              $namespaceURI = '';
3433              $qualifiedName = $name;
3434          }
3435  
3436          $currentNode =& $this->xmlDoc->createElementNS($namespaceURI, $qualifiedName);
3437          $this->lastChild->appendChild($currentNode);
3438  
3439  
3440          //add attributes
3441          reset ($attrs);
3442  
3443          while (list($key, $value) = each ($attrs)) {
3444              $colonIndex = strrpos($key, ":");
3445  
3446              if ($colonIndex !== false) {
3447                  //force to lower case because Expat for some reason forces to upper case
3448                  $namespaceURI = strtolower(substr($key, 0, $colonIndex));
3449  
3450                  $qualifiedName = $this->xmlDoc->namespaceURIMap[$namespaceURI] .
3451                      ":" . substr($key, ($colonIndex + 1));;
3452              }
3453              else {
3454                  //if containing element has a namespace, technically
3455                  //attribute namespace should be added here, but we'll do it elsewhere
3456                  //so toNormalizedString outputs the same things as is input
3457                  $namespaceURI = '';
3458                  $qualifiedName = $key;
3459              }
3460  
3461              $currentNode->setAttributeNS($namespaceURI, $qualifiedName, $value);
3462          }
3463  
3464          //and add xmlns attributes
3465          if ($this->waitingForElementToDeclareNamespaces) {
3466              //map namespace declarations to element
3467              foreach ($this->tempNamespaceURIMap as $key => $value) {
3468                  $currentNode->namespaceURIMap[$key] = $value ;
3469  
3470                  //xmlns prefix has prefix: http://www.w3.org/2000/xmlns/
3471                  $currentNode->setAttributeNS(DOMIT_XMLNS_NAMESPACE, ('xmlns:' . $value), $key);
3472              }
3473  
3474              //reset variables
3475              $this->tempNamespaceURIMap = array();
3476              $this->waitingForElementToDeclareNamespaces = false;
3477          }
3478  
3479          $this->lastChild =& $currentNode;
3480      } //startElementNS
3481  
3482  
3483      /**
3484      * Catches an end element event and processes the data
3485      * @param Object A reference to the current SAX parser
3486      * @param string The tag name of the current element
3487      */
3488  	function endElement(&$parser, $name) {
3489          if ($this->inTextNode) {
3490              $this->dumpTextNode();
3491          }
3492  
3493          $this->lastChild =& $this->lastChild->parentNode;
3494      } //endElement
3495  
3496      /**
3497      * Catches a data event and processes the text
3498      * @param Object A reference to the current SAX parser
3499      * @param string The current text data
3500      */
3501  	function dataElement(&$parser, $data) {
3502          if (!$this->inCDATASection) {
3503              $this->inTextNode = true;
3504          }
3505  
3506          $this->parseContainer .= $data;
3507      } //dataElement
3508  
3509      /**
3510      * Catches a CDATA Section event and processes the text
3511      * @param Object A reference to the current SAX parser
3512      * @param string The current text data
3513      */
3514  	function cdataElement(&$parser, $data) {
3515          $currentNode =& $this->xmlDoc->createCDATASection($data);
3516  
3517          $this->lastChild->appendChild($currentNode);
3518      } //cdataElement
3519  
3520      /**
3521      * Catches a default data event and processes the data
3522      * @param Object A reference to the current SAX parser
3523      * @param string The current data
3524      */
3525  	function defaultDataElement(&$parser, $data) {
3526          if ((strlen($data) > 2)  && ($this->parseItem == '')){
3527              $pre = strtoupper(substr($data, 0, 3));
3528  
3529              switch ($pre) {
3530                  case '<?X': //xml declaration
3531                      $this->processingInstructionElement($parser, 'xml', substr($data, 6, (strlen($data) - 6 - 2)));
3532                      break;
3533                  case '<!E': //dtd entity
3534                      $this->xmlDoc->doctype .= "\n   " . $data;
3535                      break;
3536                  case '<![': //cdata section coming
3537                      if ($this->preserveCDATA) {
3538                          $this->inCDATASection = true;
3539                      }
3540                      break;
3541                  case '<!-': //comment
3542                      $currentNode = $this->commentElement($this, substr($data, 4, (strlen($data) - 7)));
3543                      break;
3544                  case '<!D': //doctype
3545                      $this->parseItem = 'doctype';
3546                      $this->parseContainer = $data;
3547                      break;
3548                  case ']]>': //cdata end tag
3549                      if ($this->preserveCDATA) {
3550                          $currentNode =& $this->xmlDoc->createCDATASection($this->parseContainer);
3551                          $this->lastChild->appendChild($currentNode);
3552                          $this->inCDATASection = false;
3553                          $this->parseContainer = '';
3554                      }
3555                      else {
3556                          $this->dumpTextNode();
3557                      }
3558                      break;
3559              }
3560          }
3561          else {
3562              switch ($this->parseItem) {
3563                  case 'doctype':
3564                      $this->parseContainer .= $data;
3565  
3566                      if ($data == '>') {
3567                          $this->doctypeElement($parser, $this->parseContainer);
3568                          $this->parseContainer = '';
3569                          $this->parseItem = '';
3570                      }
3571                      else if ($data == '[') {
3572                          $this->parseItem = 'doctype_inline';
3573                      }
3574                      break;
3575  
3576                  case 'doctype_inline':
3577                      $this->parseContainer .= $data;
3578  
3579                      if ($data == ']') {
3580                          $this->parseItem = 'doctype';
3581                      }
3582                      else if ($data{(strlen($data) - 1)} == '>') {
3583                          $this->parseContainer .= "\n   ";
3584                      }
3585                      break;
3586              }
3587          }
3588      } //defaultDataElement
3589  
3590      /**
3591      * Catches a doctype event and processes the data
3592      * @param Object A reference to the current SAX parser
3593      * @param string The current data
3594      */
3595  	function doctypeElement(&$parser, $data) {
3596          $start = strpos($data, '<!DOCTYPE');
3597          $name = trim(substr($data, $start));
3598          $end = strpos($name, ' ');
3599          $name = substr($name, 0, $end);
3600  
3601          $currentNode = new DOMIT_DocumentType($name, $data);
3602          $currentNode->ownerDocument =& $this->xmlDoc;
3603  
3604          $this->lastChild->appendChild($currentNode);
3605          $this->xmlDoc->doctype =& $currentNode;
3606      } //doctypeElement
3607  
3608      /**
3609      * Catches a notation node event and processes the data
3610      * @param Object A reference to the current SAX parser
3611      * @param string The current notation data
3612      */
3613  	function notationElement(&$parser, $data) {
3614          //add to doctype string
3615          if (($this->parseItem == 'doctype_inline')  || ($this->parseItem == 'doctype')) {
3616              $this->parseContainer .= $data;
3617          }
3618      } //notationElement
3619  
3620      /**
3621      * Catches a comment node event and processes the data
3622      * @param Object A reference to the current SAX parser
3623      * @param string The comment data
3624      */
3625  	function commentElement(&$parser, $data) {
3626          if ($this->inTextNode) {
3627              $this->dumpTextNode();
3628          }
3629  
3630          $currentNode =& $this->xmlDoc->createComment($data);
3631          $this->lastChild->appendChild($currentNode);
3632      } //commentElement
3633  
3634      /**
3635      * Catches a processing instruction node event and processes the data
3636      * @param Object A reference to the current SAX parser
3637      * @param string The target of the processing instruction data
3638      * @param string The processing instruction data
3639      */
3640  	function processingInstructionElement(&$parser, $target, $data) {
3641          if ($this->inTextNode) {
3642              $this->dumpTextNode();
3643          }
3644  
3645          $currentNode =& $this->xmlDoc->createProcessingInstruction($target, $data);
3646          $this->lastChild->appendChild($currentNode);
3647  
3648          if (strtolower($target) == 'xml') {
3649              $this->xmlDoc->xmlDeclaration =& $currentNode;
3650          }
3651      } //processingInstructionElement
3652  
3653      /**
3654      * Catches a start namespace declaration event and processes the data
3655      * @param Object A reference to the current SAX parser
3656      * @param string The namespace prefix
3657      * @param string The namespace uri
3658      */
3659  	function startNamespaceDeclaration(&$parser, $prefix, $uri) {
3660          //make uri lower case because Expat forces it to upper case for some reason
3661          $this->xmlDoc->namespaceURIMap[strtolower($uri)] = $prefix;
3662  
3663          //set up a switch so when the target element arrives, namespaces can be mapped to it
3664          $this->waitingForElementToDeclareNamespaces = true;
3665          $this->tempNamespaceURIMap[strtolower($uri)] = $prefix;
3666      } //startNamespaceDeclaration
3667  
3668      /**
3669      * Catches an end namespace declaration event
3670      * @param Object A reference to the current SAX parser
3671      * @param string The namespace prefix
3672      */
3673  	function endNamespaceDeclaration(&$parser, $prefix) {
3674          //do nothing; could remove from map, but would hardly be optimal
3675      } //endNamespaceDeclaration
3676  
3677  } //DOMIT_Parser
3678  
3679  ?>


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