Removed 'base_path' from AkInstaller->setInstalledVersion because Ak:make_dir can...
[akelos.git] / vendor / domit / xml_domit_lite_parser.php
blobed829a9ba7f3c0a0c946b5937ddc34f7ac27d97b
1 <?php
2 /**
3 * DOMIT! Lite is a non-validating, but lightweight and fast DOM parser for PHP
4 * @package domit-xmlparser
5 * @subpackage domit-xmlparser-lite
6 * @version 0.18
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 **/
14 if (!defined('DOMIT_INCLUDE_PATH')) {
15 define('DOMIT_INCLUDE_PATH', (dirname(__FILE__) . "/"));
18 /** current version of DOMIT! Lite */
19 define ('DOMIT_LITE_VERSION', '0.18');
21 /**
22 *@global array Flipped version of $definedEntities array, to allow two-way conversion of entities
24 * Made global so that Attr nodes, which have no ownerDocument property, can access the array
26 $GLOBALS['DOMIT_defined_entities_flip'] = array();
28 require_once(DOMIT_INCLUDE_PATH . 'xml_domit_shared.php');
30 /**
31 * The base class of all DOMIT node types
33 * @package domit-xmlparser
34 * @subpackage domit-xmlparser-lite
35 * @author John Heinstein <johnkarl@nbnet.nb.ca>
37 class DOMIT_Node {
38 /** @var string The name of the node, varies according to node type */
39 var $nodeName = null;
40 /** @var string The value of the node, varies according to node type */
41 var $nodeValue = null;
42 /** @var int The type of node, e.g. CDataSection */
43 var $nodeType = null;
44 /** @var Object A reference to the parent of the current node */
45 var $parentNode = null;
46 /** @var Array An array of child node references */
47 var $childNodes = null;
48 /** @var Object A reference to the first node in the childNodes list */
49 var $firstChild = null;
50 /** @var Object A reference to the last node in the childNodes list */
51 var $lastChild = null;
52 /** @var Object A reference to the node prior to the current node in its parents childNodes list */
53 var $previousSibling = null;
54 /** @var Object A reference to the node after the current node in its parents childNodes list */
55 var $nextSibling = null;
56 /** @var Array An array of attribute key / value pairs */
57 var $attributes = null;
58 /** @var Object A reference to the Document node */
59 var $ownerDocument = null;
60 /** @var string The unique node id */
61 var $uid;
62 /** @var int The number of children of the current node */
63 var $childCount = 0;
65 /**
66 * Raises error if abstract class is directly instantiated
68 function DOMIT_Node() {
69 DOMIT_DOMException::raiseException(DOMIT_ABSTRACT_CLASS_INSTANTIATION_ERR,
70 'Cannot instantiate abstract class DOMIT_Node');
71 } //DOMIT_Node
73 /**
74 * DOMIT_Node constructor, assigns a uid
76 function _constructor() {
77 global $uidFactory;
78 $this->uid = $uidFactory->generateUID();
79 } //_constructor
81 /**
82 * Appends a node to the childNodes list of the current node
83 * @abstract
84 * @param Object The node to be appended
85 * @return Object The appended node
87 function &appendChild(&$child) {
88 DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
89 ('Method appendChild cannot be called by class ' . get_class($this)));
90 } //appendChild
92 /**
93 * Inserts a node to the childNodes list of the current node
94 * @abstract
95 * @param Object The node to be inserted
96 * @param Object The node before which the insertion is to occur
97 * @return Object The inserted node
99 function &insertBefore(&$newChild, &$refChild) {
100 DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
101 ('Method insertBefore cannot be called by class ' . get_class($this)));
102 } //insertBefore
105 * Replaces a node with another
106 * @abstract
107 * @param Object The new node
108 * @param Object The old node
109 * @return Object The new node
111 function &replaceChild(&$newChild, &$oldChild) {
112 DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
113 ('Method replaceChild cannot be called by class ' . get_class($this)));
114 } //replaceChild
117 * Removes a node from the childNodes list of the current node
118 * @abstract
119 * @param Object The node to be removed
120 * @return Object The removed node
122 function &removeChild(&$oldChild) {
123 DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
124 ('Method removeChild cannot be called by class ' . get_class($this)));
125 } //removeChild
128 * Returns the index of the specified node in a childNodes list
129 * @param Array The childNodes array to be searched
130 * @param Object The node targeted by the search
131 * @return int The index of the target node, or -1 if not found
133 function getChildNodeIndex(&$arr, &$child) {
134 $index = -1;
135 $total = count($arr);
137 for ($i = 0; $i < $total; $i++) {
138 if ($child->uid == $arr[$i]->uid) {
139 $index = $i;
140 break;
144 return $index;
145 } //getChildNodeIndex
148 * Determines whether a node has any children
149 * @return boolean True if any child nodes are present
151 function hasChildNodes() {
152 return ($this->childCount > 0);
153 } //hasChildNodes
156 * Copies a node and/or its children
157 * @abstract
158 * @param boolean True if all child nodes are also to be cloned
159 * @return Object A copy of the node and/or its children
161 function &cloneNode($deep = false) {
162 DOMIT_DOMException::raiseException(DOMIT_ABSTRACT_METHOD_INVOCATION_ERR,
163 'Cannot invoke abstract method DOMIT_Node->cloneNode($deep). Must provide an overridden method in your subclass.');
164 } //cloneNode
167 * Adds elements with the specified tag name to a NodeList collection
168 * @param Object The NodeList collection
169 * @param string The tag name of matching elements
171 function getNamedElements(&$nodeList, $tagName) {
172 //Implemented in DOMIT_Element.
173 //Needs to be here though! This is called against all nodes in the document.
174 } //getNamedElements
177 * Sets the ownerDocument property of a node to the containing DOMIT_Document
178 * @param Object A reference to the document element of the DOMIT_Document
180 function setOwnerDocument(&$rootNode) {
181 if ($rootNode->ownerDocument == null) {
182 unset($this->ownerDocument);
183 $this->ownerDocument = null;
185 else {
186 $this->ownerDocument =& $rootNode->ownerDocument;
189 $total = $this->childCount;
191 for ($i = 0; $i < $total; $i++) {
192 $this->childNodes[$i]->setOwnerDocument($rootNode);
194 } //setOwnerDocument
197 * Tests whether a value is null, and if so, returns a default value
198 * @param mixed The value to be tested
199 * @param mixed The default value
200 * @return mixed The specified value, or the default value if null
202 function &nvl(&$value,$default) {
203 if (is_null($value)) return $default;
204 return $value;
205 } //nvl
208 * Retrieves an element or DOMIT_NodeList of elements corresponding to an Xpath-like expression.
209 * @abstract
210 * @param string The query pattern
211 * @param int If a single node is to be returned (rather than the entire NodeList) the index of that node
212 * @return mixed A NodeList or single node that matches the pattern
214 function &getElementsByPath($pattern, $nodeIndex = 0) {
215 DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
216 ('Method getElementsByPath cannot be called by class ' . get_class($this)));
217 } //getElementsByPath
220 * Returns the concatented text of the current node and its children
221 * @return string The concatented text of the current node and its children
223 function getText() {
224 return $this->nodeValue;
225 } //getText
228 * Formats a string for presentation as HTML
229 * @param string The string to be formatted
230 * @param boolean True if the string is to be sent directly to output
231 * @return string The HTML formatted string
233 function forHTML($str, $doPrint = false) {
234 require_once(DOMIT_INCLUDE_PATH . 'xml_domit_utilities.php');
235 return DOMIT_Utilities::forHTML($str, $doPrint);
236 } //forHTML
239 * Generates an array representation of the node and its children
240 * @abstract
241 * @return Array A representation of the node and its children
243 function toArray() {
244 DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
245 ('Method toArray cannot be called by class ' . get_class($this)));
246 } //toArray
249 * A node event that can be set to fire upon document loading, used for node initialization
250 * @abstract
252 function onLoad() {
253 //you can override this method if you subclass any of the
254 //DOMIT_Nodes. It's a way of performing
255 //initialization of your subclass as soon as the document
256 //has been loaded (as opposed to as soon as the current node
257 //has been instantiated).
258 } //onLoad
261 * Clears previousSibling, nextSibling, and parentNode references from a node that has been removed
263 function clearReferences() {
264 if ($this->previousSibling != null) {
265 unset($this->previousSibling);
266 $this->previousSibling = null;
268 if ($this->nextSibling != null) {
269 unset($this->nextSibling);
270 $this->nextSibling = null;
272 if ($this->parentNode != null) {
273 unset($this->parentNode);
274 $this->parentNode = null;
276 } //clearReferences
279 * Generates a normalized (formatted for readability) representation of the node and its children
280 * @param boolean True if HTML readable output is desired
281 * @param boolean True if illegal xml characters in text nodes and attributes should be converted to entities
282 * @return string The formatted string representation
284 function toNormalizedString($htmlSafe = false, $subEntities=false) {
285 //require this file for generating a normalized (readable) xml string representation
286 require_once(DOMIT_INCLUDE_PATH . 'xml_domit_utilities.php');
287 global $DOMIT_defined_entities_flip;
289 $result = DOMIT_Utilities::toNormalizedString($this, $subEntities, $DOMIT_defined_entities_flip);
291 if ($htmlSafe) $result = $this->forHTML($result);
293 return $result;
294 } //toNormalizedString
295 } //DOMIT_Node
299 * A parent class for nodes which possess child nodes
301 * @package domit-xmlparser
302 * @subpackage domit-xmlparser-lite
303 * @author John Heinstein <johnkarl@nbnet.nb.ca>
305 class DOMIT_ChildNodes_Interface extends DOMIT_Node {
307 * Raises error if abstract class is directly instantiated
309 function DOMIT_ChildNodes_Interface() {
310 DOMIT_DOMException::raiseException(DOMIT_ABSTRACT_CLASS_INSTANTIATION_ERR,
311 'Cannot instantiate abstract class DOMIT_ChildNodes_Interface');
312 } //DOMIT_ChildNodes_Interface
315 * Appends a node to the childNodes list of the current node
316 * @param Object The node to be appended
317 * @return Object The appended node
319 function &appendChild(&$child) {
320 if (!($this->hasChildNodes())) {
321 $this->childNodes[0] =& $child;
322 $this->firstChild =& $child;
324 else {
325 //remove $child if it already exists
326 $index = $this->getChildNodeIndex($this->childNodes, $child);
328 if ($index != -1) {
329 $this->removeChild($child);
332 //append child
333 $numNodes = $this->childCount;
334 $prevSibling =& $this->childNodes[($numNodes - 1)];
336 $this->childNodes[$numNodes] =& $child;
338 //set next and previous relationships
339 $child->previousSibling =& $prevSibling;
340 $prevSibling->nextSibling =& $child;
343 $this->lastChild =& $child;
344 $child->parentNode =& $this;
346 unset($child->nextSibling);
347 $child->nextSibling = null;
349 $child->setOwnerDocument($this);
350 $this->childCount++;
352 return $child;
353 } //appendChild
356 * Inserts a node to the childNodes list of the current node
357 * @param Object The node to be inserted
358 * @param Object The node before which the insertion is to occur
359 * @return Object The inserted node
361 function &insertBefore(&$newChild, &$refChild) {
362 if (($refChild->nodeType == DOMIT_DOCUMENT_NODE) ||
363 ($refChild->parentNode == null)) {
365 DOMIT_DOMException::raiseException(DOMIT_NOT_FOUND_ERR,
366 'Reference child not present in the child nodes list.');
369 //if reference child is also the node to be inserted
370 //leave the document as is and don't raise an exception
371 if ($refChild->uid == $newChild->uid) {
372 return $newChild;
375 //remove $newChild if it already exists
376 $index = $this->getChildNodeIndex($this->childNodes, $newChild);
377 if ($index != -1) {
378 $this->removeChild($newChild);
381 //find index of $refChild in childNodes
382 $index = $this->getChildNodeIndex($this->childNodes, $refChild);
384 if ($index != -1) {
385 //reset sibling chain
386 if ($refChild->previousSibling != null) {
387 $refChild->previousSibling->nextSibling =& $newChild;
388 $newChild->previousSibling =& $refChild->previousSibling;
390 else {
391 $this->firstChild =& $newChild;
393 if ($newChild->previousSibling != null) {
394 unset($newChild->previousSibling);
395 $newChild->previousSibling = null;
399 $newChild->parentNode =& $refChild->parentNode;
400 $newChild->nextSibling =& $refChild;
401 $refChild->previousSibling =& $newChild;
403 //add node to childNodes
404 $i = $this->childCount;
406 while ($i >= 0) {
407 if ($i > $index) {
408 $this->childNodes[$i] =& $this->childNodes[($i - 1)];
410 else if ($i == $index) {
411 $this->childNodes[$i] =& $newChild;
413 $i--;
416 $this->childCount++;
418 else {
419 $this->appendChild($newChild);
422 $newChild->setOwnerDocument($this);
424 return $newChild;
425 } //insertBefore
428 * Replaces a node with another
429 * @param Object The new node
430 * @param Object The old node
431 * @return Object The new node
433 function &replaceChild(&$newChild, &$oldChild) {
434 if ($this->hasChildNodes()) {
435 //remove $newChild if it already exists
436 $index = $this->getChildNodeIndex($this->childNodes, $newChild);
437 if ($index != -1) {
438 $this->removeChild($newChild);
441 //find index of $oldChild in childNodes
442 $index = $this->getChildNodeIndex($this->childNodes, $oldChild);
444 if ($index != -1) {
445 $newChild->ownerDocument =& $oldChild->ownerDocument;
446 $newChild->parentNode =& $oldChild->parentNode;
448 //reset sibling chain
449 if ($oldChild->previousSibling == null) {
450 unset($newChild->previousSibling);
451 $newChild->previousSibling = null;
453 else {
454 $oldChild->previousSibling->nextSibling =& $newChild;
455 $newChild->previousSibling =& $oldChild->previousSibling;
458 if ($oldChild->nextSibling == null) {
459 unset($newChild->nextSibling);
460 $newChild->nextSibling = null;
462 else {
463 $oldChild->nextSibling->previousSibling =& $newChild;
464 $newChild->nextSibling =& $oldChild->nextSibling;
467 $this->childNodes[$index] =& $newChild;
469 if ($index == 0) $this->firstChild =& $newChild;
470 if ($index == ($this->childCount - 1)) $this->lastChild =& $newChild;
472 $newChild->setOwnerDocument($this);
474 return $newChild;
478 DOMIT_DOMException::raiseException(DOMIT_NOT_FOUND_ERR,
479 ('Reference node for replaceChild not found.'));
480 } //replaceChild
483 * Removes a node from the childNodes list of the current node
484 * @param Object The node to be removed
485 * @return Object The removed node
487 function &removeChild(&$oldChild) {
488 if ($this->hasChildNodes()) {
489 //find index of $oldChild in childNodes
490 $index = $this->getChildNodeIndex($this->childNodes, $oldChild);
492 if ($index != -1) {
493 //reset sibling chain
494 if (($oldChild->previousSibling != null) && ($oldChild->nextSibling != null)) {
495 $oldChild->previousSibling->nextSibling =& $oldChild->nextSibling;
496 $oldChild->nextSibling->previousSibling =& $oldChild->previousSibling;
498 else if (($oldChild->previousSibling != null) && ($oldChild->nextSibling == null)) {
499 $this->lastChild =& $oldChild->previousSibling;
500 unset($oldChild->previousSibling->nextSibling);
501 $oldChild->previousSibling->nextSibling = null;
503 else if (($oldChild->previousSibling == null) && ($oldChild->nextSibling != null)) {
504 unset($oldChild->nextSibling->previousSibling);
505 $oldChild->nextSibling->previousSibling = null;
506 $this->firstChild =& $oldChild->nextSibling;
508 else if (($oldChild->previousSibling == null) && ($oldChild->nextSibling == null)) {
509 unset($this->firstChild);
510 $this->firstChild = null;
511 unset($this->lastChild);
512 $this->lastChild = null;
515 $total = $this->childCount;
517 //remove node from childNodes
518 for ($i = 0; $i < $total; $i++) {
519 if ($i == ($total - 1)) {
520 array_splice($this->childNodes, $i, 1);
522 else if ($i >= $index) {
523 $this->childNodes[$i] =& $this->childNodes[($i + 1)];
527 $this->childCount--;
529 $oldChild->clearReferences();
530 return $oldChild;
534 DOMIT_DOMException::raiseException(DOMIT_NOT_FOUND_ERR,
535 ('Target node for removeChild not found.'));
536 } //removeChild
539 * Searches the element tree for an element with the specified attribute name and value.
540 * @param string The value of the attribute
541 * @param string The name of the attribute
542 * @param boolean True if the first found node is to be returned as a node instead of a nodelist
543 * @return object A NodeList of found elements, or null
545 function &getElementsByAttribute($attrName = 'id', $attrValue = '',
546 $returnFirstFoundNode = false) {
547 require_once(DOMIT_INCLUDE_PATH . 'xml_domit_nodemaps.php');
549 $nodelist =& new DOMIT_NodeList();
551 switch ($this->nodeType) {
552 case DOMIT_ELEMENT_NODE:
553 $this->_getElementsByAttribute($nodelist, $attrName = 'id', $attrValue,
554 $returnFirstFoundNode);
555 break;
557 case DOMIT_DOCUMENT_NODE:
558 if ($this->documentElement != null) {
559 $this->documentElement->_getElementsByAttribute($nodelist,
560 $attrName, $attrValue, $returnFirstFoundNode);
562 break;
565 if ($returnFirstFoundNode) {
566 if ($nodelist->getLength() > 0) {
567 return $nodelist->item(0);
569 else {
570 return null;
573 else {
574 return $nodelist;
576 } //getElementsByAttribute
579 * Searches the element tree for an element with the specified attribute name and value.
580 * @param object The node list of found elements
581 * @param string The value of the attribute
582 * @param string The name of the attribute
583 * @param boolean True if the first found node is to be returned as a node instead of a nodelist
584 * @param boolean True the node has been found
586 function _getElementsByAttribute(&$nodelist, $attrName, $attrValue,
587 $returnFirstFoundNode, $foundNode = false) {
588 if (!($foundNode && $returnFirstFoundNode)) {
589 if ($this->getAttribute($attrName) == $attrValue) {
590 $nodelist->appendNode($this);
591 $foundNode = true;
592 if ($returnFirstFoundNode) return;
595 $total = $this->childCount;
597 for ($i = 0; $i < $total; $i++) {
598 $currNode =& $this->childNodes[$i];
600 if ($currNode->nodeType == DOMIT_ELEMENT_NODE) {
601 $currNode->_getElementsByAttribute($nodelist,
602 $attrName, $attrValue,
603 $returnFirstFoundNode, $foundNode);
608 } //_getElementsByAttribute
609 } //DOMIT_ChildNodes_Interface
612 * A class representing the DOM Document
614 * @package domit-xmlparser
615 * @subpackage domit-xmlparser-lite
616 * @author John Heinstein <johnkarl@nbnet.nb.ca>
618 class DOMIT_Lite_Document extends DOMIT_ChildNodes_Interface {
619 /** @var string The xml declaration text */
620 var $xmlDeclaration;
621 /** @var string The doctype text */
622 var $doctype;
623 /** @var Object A reference to the root node of the DOM document */
624 var $documentElement;
625 /** @var string The parser used to process the DOM document, either "EXPAT" or "SAXY_LITE" */
626 var $parser;
627 /** @var Object A reference to the DOMIT_DOMImplementation object */
628 var $implementation;
629 /** @var Array User defined translation table for XML entities */
630 var $definedEntities = array();
631 /** @var boolean If true, loadXML or parseXML will attempt to detect and repair invalid xml */
632 var $doResolveErrors = false;
633 /** @var boolean If true, elements tags will be rendered to string as <element></element> rather than <element/> */
634 var $doExpandEmptyElementTags = false;
635 /** @var array A list of exceptions to the empty element expansion rule */
636 var $expandEmptyElementExceptions = array();
637 /** @var int The error code returned by the SAX parser */
638 var $errorCode = 0;
639 /** @var string The error string returned by the SAX parser */
640 var $errorString = '';
641 /** @var object A reference to a http connection or proxy server, if one is required */
642 var $httpConnection = null;
645 * DOM Document constructor
647 function DOMIT_Lite_Document() {
648 $this->_constructor();
649 $this->xmlDeclaration = '';
650 $this->doctype = '';
651 $this->documentElement = null;
652 $this->nodeType = DOMIT_DOCUMENT_NODE;
653 $this->nodeName = '#document';
654 $this->ownerDocument =& $this;
655 $this->parser = '';
656 $this->implementation =& new DOMIT_DOMImplementation();
657 } //DOMIT_Lite_Document
660 * Specifies whether DOMIT! Lite will try to fix invalid XML before parsing begins
661 * @param boolean True if errors are to be resolved
663 function resolveErrors($truthVal) {
664 $this->doResolveErrors = $truthVal;
665 } //resolveErrors
668 * Specifies the parameters of the http conection used to obtain the xml data
669 * @param string The ip address or domain name of the connection
670 * @param string The path of the connection
671 * @param int The port that the connection is listening on
672 * @param int The timeout value for the connection
673 * @param string The user name, if authentication is required
674 * @param string The password, if authentication is required
676 function setConnection($host, $path = '/', $port = 80, $timeout = 0, $user = null, $password = null) {
677 require_once(DOMIT_INCLUDE_PATH . 'php_http_client_generic.php');
679 $this->httpConnection =& new php_http_client_generic($host, $path, $port, $timeout, $user, $password);
680 } //setConnection
683 * Specifies basic authentication for an http connection
684 * @param string The user name
685 * @param string The password
687 function setAuthorization($user, $password) {
688 $this->httpConnection->setAuthorization($user, $password);
689 } //setAuthorization
692 * Specifies that a proxy is to be used to obtain the xml data
693 * @param string The ip address or domain name of the proxy
694 * @param string The path to the proxy
695 * @param int The port that the proxy is listening on
696 * @param int The timeout value for the connection
697 * @param string The user name, if authentication is required
698 * @param string The password, if authentication is required
700 function setProxyConnection($host, $path = '/', $port = 80, $timeout = 0, $user = null, $password = null) {
701 require_once(DOMIT_INCLUDE_PATH . 'php_http_proxy.php');
703 $this->httpConnection =& new php_http_proxy($host, $path, $port, $timeout, $user, $password);
704 } //setProxyConnection
707 * Specifies basic authentication for the proxy
708 * @param string The user name
709 * @param string The password
711 function setProxyAuthorization($user, $password) {
712 $this->httpConnection->setProxyAuthorization($user, $password);
713 } //setProxyAuthorization
716 * Returns the error code from the underlying SAX parser
717 * @return int The error code
719 function getErrorCode() {
720 return $this->errorCode;
721 } //getErrorCode
724 * Returns the error string from the underlying SAX parser
725 * @return string The error string
727 function getErrorString() {
728 return $this->errorString;
729 } //getErrorString
732 * Specifies whether elements tags will be rendered to string as <element></element> rather than <element/>
733 * @param boolean True if the expanded form is to be used
734 * @param mixed An array of tag names that should be excepted from expandEmptyElements rule (optional)
736 function expandEmptyElementTags($truthVal, $expandEmptyElementExceptions = false) {
737 $this->doExpandEmptyElementTags = $truthVal;
739 if (is_array($expandEmptyElementExceptions)) {
740 $this->expandEmptyElementExceptions = $expandEmptyElementExceptions;
742 } //expandEmptyElementTags
745 * Set the specified node as document element
746 * @param Object The node that is to become document element
747 * @return Object The new document element
749 function &setDocumentElement(&$node) {
750 if ($node->nodeType == DOMIT_ELEMENT_NODE) {
751 if ($this->documentElement == null) {
752 parent::appendChild($node);
754 else {
755 parent::replaceChild($node, $this->documentElement);
758 $this->documentElement =& $node;
760 else {
761 DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
762 ('Cannot add a node of type ' . get_class($node) . ' as a Document Element.'));
765 return $node;
766 } //setDocumentElement
769 * Appends a node to the childNodes list of the current node
770 * @param Object The node to be appended
771 * @return Object The appended node
773 function &appendChild(&$node) {
774 if ($node->nodeType == DOMIT_ELEMENT_NODE) {
775 if ($this->documentElement == null) {
776 parent::appendChild($node);
777 $this->setDocumentElement($node);
779 else {
780 //error thrown if documentElement already exists!
781 DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
782 ('Cannot have more than one root node (documentElement) in a DOMIT_Document.'));
785 else {
786 DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
787 ('Cannot add a node of type ' . get_class($node) . ' to a DOMIT_Document.'));
790 return $node;
791 } //appendChild
794 * Replaces a node with another
795 * @param Object The new node
796 * @param Object The old node
797 * @return Object The new node
799 function &replaceChild(&$newChild, &$oldChild) {
800 if (($this->documentElement != null) && ($oldChild->uid == $this->documentElement->uid)) {
801 if ($node->nodeType == DOMIT_ELEMENT_NODE) {
802 //replace documentElement with new node
803 $this->setDocumentElement($newChild);
805 else {
806 DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
807 ('Cannot replace Document Element with a node of class ' . get_class($newChild)));
810 else {
811 if ($node->nodeType == DOMIT_ELEMENT_NODE) {
812 if ($this->documentElement != null) {
813 DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
814 ('Cannot have more than one root node (documentElement) in a DOMIT_Document.'));
816 else {
817 parent::replaceChild($newChild, $oldChild);
820 else {
821 DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
822 ('Nodes of class ' . get_class($newChild) . ' cannot be children of a DOMIT_Document.'));
826 return $newChild;
827 } //replaceChild
830 * Inserts a node to the childNodes list of the current node
831 * @param Object The node to be inserted
832 * @param Object The node before which the insertion is to occur
833 * @return Object The inserted node
835 function &insertBefore(&$newChild, &$refChild) {
836 $type = $newChild->nodeType;
838 if ($type == DOMIT_ELEMENT_NODE) {
839 if ($this->documentElement == null) {
840 parent::insertBefore($newChild);
841 $this->setDocumentElement($newChild);
843 else {
844 //error thrown if documentElement already exists!
845 DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
846 ('Cannot have more than one root node (documentElement) in a DOMIT_Document.'));
849 else {
850 DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR,
851 ('Cannot insert a node of type ' . get_class($newChild) . ' to a DOMIT_Document.'));
854 return $newChild;
855 } //insertBefore
858 * Removes a node from the childNodes list of the current node
859 * @param Object The node to be removed
860 * @return Object The removed node
862 function &removeChild(&$oldChild) {
863 if (($this->documentElement != null) && ($oldChild->uid == $this->documentElement->uid)) {
864 parent::removeChild($oldChild);
865 $this->documentElement = null;
867 else {
868 parent::removeChild($oldChild);
871 $oldChild->clearReferences();
872 return $oldChild;
873 } //removeChild
876 * Creates a new DOMIT_Element node
877 * @param string The tag name of the element
878 * @return Object The new element
880 function &createElement($tagName) {
881 $node =& new DOMIT_Element($tagName);
882 $node->ownerDocument =& $this;
884 return $node;
885 } //createElement
888 * Creates a new DOMIT_Text node
889 * @param string The text of the node
890 * @return Object The new text node
892 function &createTextNode($data) {
893 $node =& new DOMIT_TextNode($data);
894 $node->ownerDocument =& $this;
896 return $node;
897 } //createTextNode
900 * Creates a new DOMIT_CDataSection node
901 * @param string The text of the CDATASection
902 * @return Object The new CDATASection node
904 function &createCDATASection($data) {
905 $node =& new DOMIT_CDATASection($data);
906 $node->ownerDocument =& $this;
908 return $node;
909 } //createCDATASection
912 * Retrieves a NodeList of child elements with the specified tag name
913 * @param string The matching element tag name
914 * @return Object A NodeList of found elements
916 function &getElementsByTagName($tagName) {
917 $nodeList =& new DOMIT_NodeList();
919 if ($this->documentElement != null) {
920 $this->documentElement->getNamedElements($nodeList, $tagName);
923 return $nodeList;
924 } //getElementsByTagName
927 * Retrieves an element or DOMIT_NodeList of elements corresponding to an Xpath-like expression.
928 * @param string The query pattern
929 * @param int If a single node is to be returned (rather than the entire NodeList) the index of that node
930 * @return mixed A NodeList or single node that matches the pattern
932 function &getElementsByPath($pattern, $nodeIndex = 0) {
933 require_once(DOMIT_INCLUDE_PATH . 'xml_domit_getelementsbypath.php');
935 $gebp = new DOMIT_GetElementsByPath();
936 $myResponse =& $gebp->parsePattern($this, $pattern, $nodeIndex);
938 return $myResponse;
939 } //getElementsByPath
942 * Parses an xml string; first encodes string as UTF-8
943 * @param string The xml text to be parsed
944 * @param boolean True if SAXY is to be used instead of Expat
945 * @param boolean False if CDATA Section are to be generated as Text nodes
946 * @param boolean True if onLoad is to be called on each node after parsing
947 * @return boolean True if parsing is successful
949 function parseXML_utf8($xmlText, $useSAXY = true, $preserveCDATA = true, $fireLoadEvent = false) {
950 return $this->parseXML(utf8_encode($xmlText), $useSAXY, $preserveCDATA, $fireLoadEvent);
951 } //parseXML_utf8
954 * Parses an xml string
955 * @param string The xml text to be parsed
956 * @param boolean True if SAXY is to be used instead of Expat
957 * @param boolean False if CDATA Section are to be generated as Text nodes
958 * @param boolean True if onLoad is to be called on each node after parsing
959 * @return boolean True if parsing is successful
961 function parseXML($xmlText, $useSAXY = true, $preserveCDATA = true, $fireLoadEvent = false) {
962 require_once(DOMIT_INCLUDE_PATH . 'xml_domit_utilities.php');
964 if ($this->doResolveErrors) {
965 require_once(DOMIT_INCLUDE_PATH . 'xml_domit_doctor.php');
966 $xmlText = DOMIT_Doctor::fixAmpersands($xmlText);
969 if (DOMIT_Utilities::validateXML($xmlText)) {
970 $domParser =& new DOMIT_Parser();
972 if ($useSAXY || (!function_exists('xml_parser_create'))) {
973 //use SAXY parser to populate xml tree
974 $this->parser = 'SAXY_LITE';
975 $success = $domParser->parseSAXY($this, $xmlText, $preserveCDATA, $this->definedEntities);
977 else {
978 //use Expat parser to populate xml tree
979 $this->parser = 'EXPAT';
980 $success = $domParser->parse($this, $xmlText, $preserveCDATA);
983 if ($fireLoadEvent && ($this->documentElement != null)) $this->load($this->documentElement);
985 return $success;
987 else {
988 return false;
990 } //parseXML
993 * Parses an xml file; first encodes text as UTF-8
994 * @param string The xml file to be parsed
995 * @param boolean True if SAXY is to be used instead of Expat
996 * @param boolean False if CDATA Section are to be generated as Text nodes
997 * @param boolean True if onLoad is to be called on each node after parsing
998 * @return boolean True if parsing is successful
1000 function loadXML_utf8($filename, $useSAXY = true, $preserveCDATA = true, $fireLoadEvent = false) {
1001 $xmlText = $this->getTextFromFile($filename);
1002 return $this->parseXML_utf8($xmlText, $useSAXY, $preserveCDATA, $fireLoadEvent);
1003 } //loadXML_utf8
1006 * Parses an xml file
1007 * @param string The xml file to be parsed
1008 * @param boolean True if SAXY is to be used instead of Expat
1009 * @param boolean False if CDATA Section are to be generated as Text nodes
1010 * @param boolean True if onLoad is to be called on each node after parsing
1011 * @return boolean True if parsing is successful
1013 function loadXML($filename, $useSAXY = true, $preserveCDATA = true, $fireLoadEvent = false) {
1014 $xmlText = $this->getTextFromFile($filename);
1015 return $this->parseXML($xmlText, $useSAXY, $preserveCDATA, $fireLoadEvent);
1016 } //loadXML
1019 * Retrieves text from a file
1020 * @param string The file path
1021 * @return string The text contained in the file
1023 function getTextFromFile($filename) {
1024 if ($this->httpConnection != null) {
1025 $response =& $this->httpConnection->get($filename);
1026 $this->httpConnection->disconnect();
1027 return $response->getResponse();
1029 else if (function_exists('file_get_contents')) {
1030 //if (file_exists($filename)) {
1031 return file_get_contents($filename);
1034 else {
1035 require_once(DOMIT_INCLUDE_PATH . 'php_file_utilities.php');
1037 $fileContents =& php_file_utilities::getDataFromFile($filename, 'r');
1038 return $fileContents;
1041 return '';
1042 } //getTextFromFile
1045 * Saves the current DOM document as an xml file; first encodes text as UTF-8
1046 * @param string The path of the xml file
1047 * @param boolean True if xml text is to be normalized before saving
1048 * @return boolean True if save is successful
1050 function saveXML_utf8($filename, $normalized=false) {
1051 if ($normalized) {
1052 $stringRep = $this->toNormalizedString(false, true); //param 2 is $subEntities
1054 else {
1055 $stringRep = $this->toString(false, true);
1058 return $this->saveTextToFile($filename, utf8_encode($stringRep));
1059 } //saveXML_utf8
1062 * Saves the current DOM document as an xml file
1063 * @param string The path of the xml file
1064 * @param boolean True if xml text is to be normalized before saving
1065 * @return boolean True if save is successful
1067 function saveXML($filename, $normalized=false) {
1068 if ($normalized) {
1069 $stringRep = $this->toNormalizedString(false, true);
1071 else {
1072 $stringRep = $this->toString(false, true);
1075 return $this->saveTextToFile($filename, $stringRep);
1076 } //saveXML
1079 * Saves text to a file
1080 * @param string The file path
1081 * @param string The text to be saved
1082 * @return boolean True if the save is successful
1084 function saveTextToFile($filename, $text) {
1085 if (function_exists('file_put_contents')) {
1086 file_put_contents($filename, $text);
1088 else {
1089 require_once(DOMIT_INCLUDE_PATH . 'php_file_utilities.php');
1090 php_file_utilities::putDataToFile($filename, $text, 'w');
1093 return (file_exists($filename) && is_writable($filename));
1094 } //saveTextToFile
1097 * Indicates the SAX parser used to parse the current document
1098 * @return string Either "SAXY_LITE" or "EXPAT"
1100 function parsedBy() {
1101 return $this->parser;
1102 } //parsedBy
1105 * Returns the concatented text of the current node and its children
1106 * @return string The concatented text of the current node and its children
1108 function getText() {
1109 if ($this->documentElement != null) {
1110 $root =& $this->documentElement;
1111 return $root->getText();
1113 else {
1114 return '';
1116 } //getText
1119 * Returns the doctype text
1120 * @return string The doctype text, or an emty string
1122 function getDocType() {
1123 return $this->doctype;
1124 } //getDocType
1127 * Returns the xml declaration text
1128 * @return mixed The xml declaration text, or an empty string
1130 function getXMLDeclaration() {
1131 return $this->xmlDeclaration;
1132 } //getXMLDeclaration
1135 * Returns a reference to the DOMIT_DOMImplementation object
1136 * @return Object A reference to the DOMIT_DOMImplementation object
1138 function &getDOMImplementation() {
1139 return $this->implementation;
1140 } //getDOMImplementation
1143 * Manages the firing of the onLoad() event
1144 * @param Object The parent node of the current recursion
1146 function load(&$contextNode) {
1147 $total = $contextNode->childCount;
1149 for ($i = 0; $i < $total; $i++) {
1150 $currNode =& $contextNode->childNodes[$i];
1151 $currNode->ownerDocument->load($currNode);
1154 $contextNode->onLoad();
1155 } //load
1158 * Returns the current version of DOMIT! Lite
1159 * @return Object The current version of DOMIT! Lite
1161 function getVersion() {
1162 return DOMIT_LITE_VERSION;
1163 } //getVersion
1166 * Appends an array of entity mappings to the existing translation table
1168 * Intended mainly to facilitate the conversion of non-ASCII entities into equivalent characters
1170 * @param array A list of entity mappings in the format: array('&amp;' => '&');
1172 function appendEntityTranslationTable($table) {
1173 $this->definedEntities = $table;
1175 global $DOMIT_defined_entities_flip;
1176 $DOMIT_defined_entities_flip = array_flip($table);
1177 } //appendEntityTranslationTable
1180 * Generates an array representation of the node and its children
1181 * @return Array A representation of the node and its children
1183 function toArray() {
1184 $arReturn = array($this->nodeName => array());
1185 $total = $this->childCount;
1187 for ($i = 0; $i < $total; $i++) {
1188 $arReturn[$this->nodeName][$i] = $this->childNodes[$i]->toArray();
1191 return $arReturn;
1192 } //toArray
1195 * Copies a node and/or its children
1196 * @param boolean True if all child nodes are also to be cloned
1197 * @return Object A copy of the node and/or its children
1199 function &cloneNode($deep = false) {
1200 $className = get_class($this);
1201 $clone =& new $className($this->nodeName);
1203 if ($deep) {
1204 $total = $this->childCount;
1206 for ($i = 0; $i < $total; $i++) {
1207 $currentChild =& $this->childNodes[$i];
1208 $clone->appendChild($currentChild->cloneNode($deep));
1212 return $clone;
1213 } //cloneNode
1216 * Generates a string representation of the node and its children
1217 * @param boolean True if HTML readable output is desired
1218 * @param boolean True if illegal xml characters in text nodes and attributes should be converted to entities
1219 * @return string The string representation
1221 function toString($htmlSafe = false, $subEntities=false) {
1222 $result = '';
1223 $total = $this->childCount;
1225 for ($i = 0; $i < $total; $i++) {
1226 $result .= $this->childNodes[$i]->toString(false, $subEntities);
1229 if ($htmlSafe) $result = $this->forHTML($result);
1231 return $result;
1232 } //toString
1233 } //DOMIT_Lite_Document
1236 * A class representing the DOM Element
1238 * @package domit-xmlparser
1239 * @subpackage domit-xmlparser-lite
1240 * @author John Heinstein <johnkarl@nbnet.nb.ca>
1242 class DOMIT_Element extends DOMIT_ChildNodes_Interface {
1244 * DOM Element constructor
1245 * @param string The tag name of the element
1247 function DOMIT_Element($tagName) {
1248 $this->_constructor();
1249 $this->nodeType = DOMIT_ELEMENT_NODE;
1250 $this->nodeName = $tagName;
1251 $this->attributes = array();
1252 $this->childNodes = array();
1253 } //DOMIT_Element
1256 * Returns the tag name of the element
1257 * @return string The tag name of the element
1259 function getTagName() {
1260 return $this->nodeName;
1261 } //getTagName
1264 * Adds elements with the specified tag name to a NodeList collection
1265 * @param Object The NodeList collection
1266 * @param string The tag name of matching elements
1268 function getNamedElements(&$nodeList, $tagName) {
1269 if (($this->nodeName == $tagName) || ($tagName == '*')) {
1270 $nodeList->appendNode($this);
1273 $total = $this->childCount;
1275 for ($i = 0; $i < $total; $i++) {
1276 $this->childNodes[$i]->getNamedElements($nodeList, $tagName);
1278 } //getNamedElements
1281 * Returns the concatented text of the current node and its children
1282 * @return string The concatented text of the current node and its children
1284 function getText() {
1285 $text = '';
1286 $numChildren = $this->childCount;
1288 for ($i = 0; $i < $numChildren; $i++) {
1289 $child =& $this->childNodes[$i];
1290 $text .= $child->getText();
1293 return $text;
1294 } //getText
1297 * If a child text node exists, sets the nodeValue to $data. A child text node is created if none exists
1298 * @param string The text data of the node
1300 function setText($data) {
1301 switch ($this->childCount) {
1302 case 1:
1303 if ($this->firstChild->nodeType == DOMIT_TEXT_NODE) {
1304 $this->firstChild->setText($data);
1306 break;
1308 case 0:
1309 $childTextNode =& $this->ownerDocument->createTextNode($data);
1310 $this->appendChild($childTextNode);
1311 break;
1313 default:
1314 //do nothing. Maybe throw error???
1316 } //setText
1319 * Retrieves a NodeList of child elements with the specified tag name
1320 * @param string The matching element tag name
1321 * @return Object A NodeList of found elements
1323 function &getElementsByTagName($tagName) {
1324 $nodeList =& new DOMIT_NodeList();
1325 $this->getNamedElements($nodeList, $tagName);
1327 return $nodeList;
1328 } //getElementsByTagName
1331 * Retrieves an element or DOMIT_NodeList of elements corresponding to an Xpath-like expression.
1332 * @param string The query pattern
1333 * @param int If a single node is to be returned (rather than the entire NodeList) the index of that node
1334 * @return mixed A NodeList or single node that matches the pattern
1336 function &getElementsByPath($pattern, $nodeIndex = 0) {
1337 require_once(DOMIT_INCLUDE_PATH . 'xml_domit_getelementsbypath.php');
1339 $gebp = new DOMIT_GetElementsByPath();
1340 $myResponse =& $gebp->parsePattern($this, $pattern, $nodeIndex);
1342 return $myResponse;
1343 } //getElementsByPath
1346 * Gets the value of the specified attribute, if it exists
1347 * @param string The attribute name
1348 * @return string The attribute value
1350 function getAttribute($name) {
1351 if ($this->hasAttribute($name)) {
1352 return $this->attributes[$name];
1354 } //getAttribute
1357 * Sets the value of the specified attribute; creates a new attribute if one doesn't exist
1358 * @param string The attribute name
1359 * @param string The desired attribute value
1361 function setAttribute($name, $value) {
1362 $this->attributes[$name] = $value;
1363 } //setAttribute
1366 * Removes the specified attribute
1367 * @param string The name of the attribute to be removed
1369 function removeAttribute($name) {
1370 if ($this->hasAttribute($name)) {
1371 unset($this->attributes[$name]);
1373 } //removeAttribute
1376 * Determines whether an attribute with the specified name exists
1377 * @param string The name of the attribute
1378 * @return boolean True if the attribute exists
1380 function hasAttribute($name) {
1381 return isset($this->attributes[$name]);
1382 } //hasAttribute
1385 * Collapses adjacent text nodes in entire element subtree
1387 function normalize() {
1388 if ($this->hasChildNodes()) {
1389 $currNode =& $this->childNodes[0];
1391 while ($currNode->nextSibling != null) {
1392 $nextNode =& $currNode->nextSibling;
1394 if (($currNode->nodeType == DOMIT_TEXT_NODE) &&
1395 ($nextNode->nodeType == DOMIT_TEXT_NODE)) {
1396 $currNode->nodeValue .= $nextNode->nodeValue;
1397 $this->removeChild($nextNode);
1399 else {
1400 $currNode->normalize();
1403 if ($currNode->nextSibling != null) {
1404 $currNode =& $currNode->nextSibling;
1408 } //normalize
1411 * Generates an array representation of the node and its children
1412 * @return Array A representation of the node and its children
1414 function toArray() {
1415 $arReturn = array($this->nodeName => array("attributes" => $this->attributes));
1416 $total = $this->childCount;
1418 for ($i = 0; $i < $total; $i++) {
1419 $arReturn[$this->nodeName][$i] = $this->childNodes[$i]->toArray();
1422 return $arReturn;
1423 } //toArray
1426 * Copies a node and/or its children
1427 * @param boolean True if all child nodes are also to be cloned
1428 * @return Object A copy of the node and/or its children
1430 function &cloneNode($deep = false) {
1431 $className = get_class($this);
1432 $clone =& new $className($this->nodeName);
1434 $clone->attributes = $this->attributes;
1436 if ($deep) {
1437 $total = $this->childCount;
1439 for ($i = 0; $i < $total; $i++) {
1440 $currentChild =& $this->childNodes[$i];
1441 $clone->appendChild($currentChild->cloneNode($deep));
1445 return $clone;
1446 } //cloneNode
1449 * Generates a string representation of the node and its children
1450 * @param boolean True if HTML readable output is desired
1451 * @param boolean True if illegal xml characters in text nodes and attributes should be converted to entities
1452 * @return string The string representation
1454 function toString($htmlSafe = false, $subEntities=false) {
1455 require_once(DOMIT_INCLUDE_PATH . 'xml_domit_utilities.php');
1456 global $DOMIT_defined_entities_flip;
1458 $result = '<' . $this->nodeName;
1460 //get attributes
1461 foreach ($this->attributes as $key => $value) {
1462 $result .= ' ' . $key . '="';
1463 $result .= ($subEntities ? DOMIT_Utilities::convertEntities($value,
1464 $DOMIT_defined_entities_flip) : $value);
1465 $result .= '"';
1468 //get children
1469 $myNodes =& $this->childNodes;
1470 $total = count($myNodes);
1472 if ($total != 0) {
1473 $result .= '>';
1475 for ($i = 0; $i < $total; $i++) {
1476 $child =& $myNodes[$i];
1477 $result .= $child->toString(false, $subEntities);
1480 $result .= '</' . $this->nodeName . '>';
1482 else {
1483 if ($this->ownerDocument->doExpandEmptyElementTags) {
1484 if (in_array($this->nodeName, $this->ownerDocument->expandEmptyElementExceptions)) {
1485 $result .= ' />';
1487 else {
1488 $result .= '></' . $this->nodeName . '>';
1491 else {
1492 if (in_array($this->nodeName, $this->ownerDocument->expandEmptyElementExceptions)) {
1493 $result .= '></' . $this->nodeName . '>';
1495 else {
1496 $result .= ' />';
1501 if ($htmlSafe) $result = $this->forHTML($result);
1503 return $result;
1504 } //toString
1505 } //DOMIT_Element
1508 * A class representing the DOM Text Node
1510 * @package domit-xmlparser
1511 * @subpackage domit-xmlparser-lite
1512 * @author John Heinstein <johnkarl@nbnet.nb.ca>
1514 class DOMIT_TextNode extends DOMIT_Node {
1516 * DOM Text Node constructor
1517 * @param string The text of the node
1519 function DOMIT_TextNode($data) {
1520 $this->_constructor();
1521 $this->nodeType = DOMIT_TEXT_NODE;
1522 $this->nodeName = '#text';
1523 $this->setText($data);
1524 } //DOMIT_TextNode
1527 * Returns the text contained in the current node
1528 * @return string The text of the current node
1530 function getText() {
1531 return $this->nodeValue;
1532 } //getText
1535 * Sets the text contained in the current node to $data.
1536 * @param string The text data of the node
1538 function setText($data) {
1539 $this->nodeValue = $data;
1540 } //setText
1543 * Generates an array representation of the node and its children
1544 * @return Array A representation of the node and its children
1546 function toArray() {
1547 return $this->toString();
1548 } //toArray
1551 * Copies a node and/or its children
1552 * @param boolean True if all child nodes are also to be cloned
1553 * @return Object A copy of the node and/or its children
1555 function &cloneNode($deep = false) {
1556 $className = get_class($this);
1557 $clone =& new $className($this->nodeValue);
1559 return $clone;
1560 } //cloneNode
1563 * Generates a string representation of the node and its children
1564 * @param boolean True if HTML readable output is desired
1565 * @param boolean True if illegal xml characters should be converted to entities
1566 * @return string The string representation
1568 function toString($htmlSafe = false, $subEntities=false) {
1569 require_once(DOMIT_INCLUDE_PATH . 'xml_domit_utilities.php');
1570 global $DOMIT_defined_entities_flip;
1572 $result = ($subEntities ? DOMIT_Utilities::convertEntities($this->nodeValue,
1573 $DOMIT_defined_entities_flip) : $this->nodeValue);
1575 if ($htmlSafe) $result = $this->forHTML($result);
1577 return $result;
1578 } //toString
1579 } //DOMIT_TextNode
1582 * A class representing the DOM CDATA Section
1584 * @package domit-xmlparser
1585 * @subpackage domit-xmlparser-lite
1586 * @author John Heinstein <johnkarl@nbnet.nb.ca>
1588 class DOMIT_CDATASection extends DOMIT_TextNode {
1590 * DOM CDATA Section node constructor
1591 * @param string The text of the node
1593 function DOMIT_CDATASection($data) {
1594 $this->_constructor();
1595 $this->nodeType = DOMIT_CDATA_SECTION_NODE;
1596 $this->nodeName = '#cdata-section';
1597 $this->setText($data);
1598 } //DOMIT_CDATASection
1601 * Generates a string representation of the node and its children
1602 * @param boolean True if HTML readable output is desired
1603 * @param boolean True if illegal xml characters should be converted to entities
1604 * @return string The string representation
1606 function toString($htmlSafe = false, $subEntities=false) {
1607 $result = '<![CDATA[';
1608 $result .= $subEntities ? str_replace("]]>", "]]&gt;", $this->nodeValue) :
1609 $this->nodeValue;
1610 $result .= ']]>';
1612 if ($htmlSafe) $result = $this->forHTML($result);
1614 return $result;
1615 } //toString
1616 } //DOMIT_CDATASection
1619 * Manages the generation of a DOMIT! document from SAX events
1621 * @package domit-xmlparser
1622 * @subpackage domit-xmlparser-lite
1623 * @author John Heinstein <johnkarl@nbnet.nb.ca>
1625 class DOMIT_Parser {
1626 /** @var Object A reference to the resulting xmldoc */
1627 var $xmlDoc = null;
1628 /** @var Object A reference to the current node in the parsing process */
1629 var $currentNode = null;
1630 /** @var Object A reference to the last child in the parsing process */
1631 var $lastChild = null;
1632 /** @var boolean True if currently parsing a CDATA Section */
1633 var $inCDATASection = false; //flag for Expat
1634 /** @var boolean True if currently parsing a Text node */
1635 var $inTextNode = false;
1636 /** @var boolean True is CDATA Section nodes are not to be converted into Text nodes */
1637 var $preserveCDATA;
1638 /** @var string A container for holding the currently parsed text data */
1639 var $parseContainer = '';
1640 /** @var string The current docutype text */
1641 var $parseItem = '';
1644 * Parses xml text using Expat
1645 * @param Object A reference to the DOM document that the xml is to be parsed into
1646 * @param string The text to be parsed
1647 * @param boolean True if CDATA Section nodes are not to be converted into Text nodes
1648 * @return boolean True if the parsing is successful
1650 function parse (&$myXMLDoc, $xmlText, $preserveCDATA = true) {
1651 $this->xmlDoc =& $myXMLDoc;
1652 $this->lastChild =& $this->xmlDoc;
1654 $this->preserveCDATA = $preserveCDATA;
1656 //create instance of expat parser (should be included in php distro)
1657 if (version_compare(phpversion(), '5.0', '<=')) {
1658 $parser =& xml_parser_create('');
1660 else {
1661 $parser =& xml_parser_create();
1664 //set handlers for SAX events
1665 xml_set_object($parser, $this);
1666 xml_set_element_handler($parser, 'startElement', 'endElement');
1667 xml_set_character_data_handler($parser, 'dataElement');
1668 xml_set_default_handler($parser, 'defaultDataElement');
1669 xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
1670 xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
1672 //parse out whitespace - (XML_OPTION_SKIP_WHITE = 1 does not
1673 //seem to work consistently across versions of PHP and Expat
1674 $xmlText = eregi_replace('>' . "[[:space:]]+" . '<' , '><', $xmlText);
1676 $success = xml_parse($parser, $xmlText);
1678 $this->xmlDoc->errorCode = xml_get_error_code($parser);
1679 $this->xmlDoc->errorString = xml_error_string($this->xmlDoc->errorCode);
1681 xml_parser_free($parser);
1683 return $success;
1684 } //parse
1687 * Parses xml text using SAXY
1688 * @param Object A reference to the DOM document that the xml is to be parsed into
1689 * @param string The text to be parsed
1690 * @param boolean True if CDATA Section nodes are not to be converted into Text nodes
1691 * @return boolean True if the parsing is successful
1693 function parseSAXY(&$myXMLDoc, $xmlText, $preserveCDATA, $definedEntities) {
1694 require_once(DOMIT_INCLUDE_PATH . 'xml_saxy_lite_parser.php');
1696 $this->xmlDoc =& $myXMLDoc;
1697 $this->lastChild =& $this->xmlDoc;
1699 //create instance of SAXY parser
1700 $parser =& new SAXY_Lite_Parser();
1701 $parser->appendEntityTranslationTable($definedEntities);
1703 $parser->xml_set_element_handler(array(&$this, 'startElement'), array(&$this, 'endElement'));
1704 $parser->xml_set_character_data_handler(array(&$this, 'dataElement'));
1706 if ($preserveCDATA) {
1707 $parser->xml_set_cdata_section_handler(array(&$this, 'cdataElement'));
1710 $success = $parser->parse($xmlText);
1712 $this->xmlDoc->errorCode = $parser->xml_get_error_code();
1713 $this->xmlDoc->errorString = $parser->xml_error_string($this->xmlDoc->errorCode);
1715 return $success;
1716 } //parseSAXY
1719 * Generates and appends a new text node from the parseContainer text
1721 function dumpTextNode() {
1722 //traps for mixed content
1723 $currentNode =& $this->xmlDoc->createTextNode($this->parseContainer);
1724 $this->lastChild->appendChild($currentNode);
1725 $this->inTextNode = false;
1726 $this->parseContainer = '';
1727 } //dumpTextNode
1730 * Catches a start element event and processes the data
1731 * @param Object A reference to the current SAX parser
1732 * @param string The tag name of the current element
1733 * @param Array An array of the element attributes
1735 function startElement(&$parser, $name, $attrs) {
1736 if ($this->inTextNode) {
1737 $this->dumpTextNode();
1740 $currentNode =& $this->xmlDoc->createElement($name);
1741 $currentNode->attributes = $attrs;
1742 $this->lastChild->appendChild($currentNode);
1743 $this->lastChild =& $currentNode;
1744 } //startElement
1747 * Catches an end element event and processes the data
1748 * @param Object A reference to the current SAX parser
1749 * @param string The tag name of the current element
1751 function endElement(&$parser, $name) {
1752 if ($this->inTextNode) {
1753 $this->dumpTextNode();
1756 $this->lastChild =& $this->lastChild->parentNode;
1757 } //endElement
1760 * Catches a data event and processes the text
1761 * @param Object A reference to the current SAX parser
1762 * @param string The current text data
1764 function dataElement(&$parser, $data) {
1765 if (!$this->inCDATASection) $this->inTextNode = true;
1767 $this->parseContainer .= $data;
1768 } //dataElement
1771 * Catches a CDATA Section event and processes the text
1772 * @param Object A reference to the current SAX parser
1773 * @param string The current text data
1775 function cdataElement(&$parser, $data) {
1776 $currentNode =& $this->xmlDoc->createCDATASection($data);
1778 $this->lastChild->appendChild($currentNode);
1779 } //cdataElement
1782 * Catches a default data event and processes the data
1783 * @param Object A reference to the current SAX parser
1784 * @param string The current data
1786 function defaultDataElement(&$parser, $data) {
1787 if (strlen($data) > 2){
1788 $pre = strtoupper(substr($data, 0, 3));
1790 switch ($pre) {
1791 case '<![': //cdata section coming
1792 if ($this->preserveCDATA) {
1793 $this->inCDATASection = true;
1795 break;
1796 case ']]>': //cdata remnant - ignore
1797 $currentNode =& $this->xmlDoc->createCDATASection($this->parseContainer);
1798 $this->lastChild->appendChild($currentNode);
1799 $this->inCDATASection = false;
1800 $this->parseContainer = '';
1801 break;
1804 } //defaultDataElement
1805 } //DOMIT_Parser