3 * DOMIT! is a non-validating, but lightweight and fast DOM parser for PHP
4 * @package domit-xmlparser
5 * @subpackage domit-xmlparser-main
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
14 if (!defined('DOMIT_INCLUDE_PATH')) {
15 define('DOMIT_INCLUDE_PATH', (dirname(__FILE__
) . "/"));
18 /** current version of DOMIT! */
19 define ('DOMIT_VERSION', '0.99');
21 /** current version of SAXY */
22 define ('DOMIT_XML_NAMESPACE', 'http://www.w3.org/xml/1998/namespace');
25 *@global array Flipped version of $definedEntities array, to allow two-way conversion of entities
27 * Made global so that Attr nodes, which have no ownerDocument property, can access the array
29 $GLOBALS['DOMIT_defined_entities_flip'] = array();
31 require_once(DOMIT_INCLUDE_PATH
. 'xml_domit_shared.php');
34 * The base class of all DOMIT node types
36 * @package domit-xmlparser
37 * @subpackage domit-xmlparser-main
38 * @author John Heinstein <johnkarl@nbnet.nb.ca>
41 /** @var string The name of the node, varies according to node type */
43 /** @var string The value of the node, varies according to node type */
44 var $nodeValue = null;
45 /** @var int The type of node, e.g. CDataSection */
47 /** @var Object A reference to the parent of the current node */
48 var $parentNode = null;
49 /** @var Array An array of child node references */
50 var $childNodes = null;
51 /** @var Object A reference to the first node in the childNodes list */
52 var $firstChild = null;
53 /** @var Object A reference to the last node in the childNodes list */
54 var $lastChild = null;
55 /** @var Object A reference to the node prior to the current node in its parents childNodes list */
56 var $previousSibling = null;
57 /** @var Object A reference to the node after the current node in its parents childNodes list */
58 var $nextSibling = null;
59 /** @var Object A NodeList of attribute nodes */
60 var $attributes = null;
61 /** @var Object A reference to the Document node */
62 var $ownerDocument = null;
63 /** @var String A URI that identifies the XML namespace to which the node belongs */
64 var $namespaceURI = null;
65 /** @var String The namespace prefix for the node */
67 /** @var String The local name of the node */
68 var $localname = null;
69 /** @var string The unique node id */
71 /** @var int The number of children of the current node */
75 * Raises error if abstract class is directly instantiated
77 function DOMIT_Node() {
78 DOMIT_DOMException
::raiseException(DOMIT_ABSTRACT_CLASS_INSTANTIATION_ERR
,
79 'Cannot instantiate abstract class DOMIT_Node');
83 * DOMIT_Node constructor, assigns a uid
85 function _constructor() {
87 $this->uid
= $uidFactory->generateUID();
91 * Appends a node to the childNodes list of the current node
93 * @param Object The node to be appended
94 * @return Object The appended node
96 function &appendChild(&$child) {
97 DOMIT_DOMException
::raiseException(DOMIT_HIERARCHY_REQUEST_ERR
,
98 ('Method appendChild cannot be called by class ' . get_class($this)));
102 * Inserts a node to the childNodes list of the current node
104 * @param Object The node to be inserted
105 * @param Object The node before which the insertion is to occur
106 * @return Object The inserted node
108 function &insertBefore(&$newChild, &$refChild) {
109 DOMIT_DOMException
::raiseException(DOMIT_HIERARCHY_REQUEST_ERR
,
110 ('Method insertBefore cannot be called by class ' . get_class($this)));
114 * Replaces a node with another
116 * @param Object The new node
117 * @param Object The old node
118 * @return Object The new node
120 function &replaceChild(&$newChild, &$oldChild) {
121 DOMIT_DOMException
::raiseException(DOMIT_HIERARCHY_REQUEST_ERR
,
122 ('Method replaceChild cannot be called by class ' . get_class($this)));
126 * Removes a node from the childNodes list of the current node
128 * @param Object The node to be removed
129 * @return Object The removed node
131 function &removeChild(&$oldChild) {
132 DOMIT_DOMException
::raiseException(DOMIT_HIERARCHY_REQUEST_ERR
,
133 ('Method removeChild cannot be called by class ' . get_class($this)));
137 * Returns the index of the specified node in a childNodes list
138 * @param Array The childNodes array to be searched
139 * @param Object The node targeted by the search
140 * @return int The index of the target node, or -1 if not found
142 function getChildNodeIndex(&$arr, &$child) {
144 $total = count($arr);
146 for ($i = 0; $i < $total; $i++
) {
147 if ($child->uid
== $arr[$i]->uid
) {
154 } //getChildNodeIndex
157 * Determines whether a node has any children
158 * @return boolean True if any child nodes are present
160 function hasChildNodes() {
161 return ($this->childCount
> 0);
165 * Determines whether a node has any attributes
166 * @return boolean True if the node has attributes
168 function hasAttributes() {
169 //overridden in DOMIT_Element
174 * Collapses adjacent text nodes in entire node subtree
176 function normalize() {
177 if (($this->nodeType
== DOMIT_DOCUMENT_NODE
) && ($this->documentElement
!= null)) {
178 $this->documentElement
->normalize();
183 * Copies a node and/or its children
185 * @param boolean True if all child nodes are also to be cloned
186 * @return Object A copy of the node and/or its children
188 function &cloneNode($deep = false) {
189 DOMIT_DOMException
::raiseException(DOMIT_ABSTRACT_METHOD_INVOCATION_ERR
,
190 'Cannot invoke abstract method DOMIT_Node->cloneNode($deep). Must provide an overridden method in your subclass.');
194 * Adds elements with the specified tag name to a NodeList collection
195 * @param Object The NodeList collection
196 * @param string The tag name of matching elements
198 function getNamedElements(&$nodeList, $tagName) {
199 //Implemented in DOMIT_Element.
200 //Needs to be here though! This is called against all nodes in the document.
204 * Sets the ownerDocument property of a node to the containing DOMIT_Document
205 * @param Object A reference to the document element of the DOMIT_Document
207 function setOwnerDocument(&$rootNode) {
208 if ($rootNode->ownerDocument
== null) {
209 unset($this->ownerDocument
);
210 $this->ownerDocument
= null;
213 $this->ownerDocument
=& $rootNode->ownerDocument
;
216 $total = $this->childCount
;
218 for ($i = 0; $i < $total; $i++
) {
219 $this->childNodes
[$i]->setOwnerDocument($rootNode);
224 * Tests whether a value is null, and if so, returns a default value
225 * @param mixed The value to be tested
226 * @param mixed The default value
227 * @return mixed The specified value, or the default value if null
229 function &nvl(&$value,$default) {
230 if (is_null($value)) return $default;
235 * Performs an XPath query (NOT YET IMPLEMENTED!)
236 * @param string The query pattern
237 * @return Object A NodeList containing the found nodes
239 function &selectNodes($pattern) {
240 require_once(DOMIT_INCLUDE_PATH
. 'xml_domit_xpath.php');
242 $xpParser =& new DOMIT_XPath();
244 return $xpParser->parsePattern($this, $pattern);
248 * Retrieves an element or DOMIT_NodeList of elements corresponding to an Xpath-like expression.
250 * @param string The query pattern
251 * @param int If a single node is to be returned (rather than the entire NodeList) the index of that node
252 * @return mixed A NodeList or single node that matches the pattern
254 function &getElementsByPath($pattern, $nodeIndex = 0) {
255 DOMIT_DOMException
::raiseException(DOMIT_HIERARCHY_REQUEST_ERR
,
256 ('Method getElementsByPath cannot be called by class ' . get_class($this)));
257 } //getElementsByPath
260 * Retrieves an element or DOMIT_NodeList of elements corresponding to an Xpath-like attribute expression (NOT YET IMPLEMENTED!)
262 * @param string The query pattern
263 * @param int If a single node is to be returned (rather than the entire NodeList) the index of that node
264 * @return mixed A NodeList or single node that matches the pattern
266 function &getElementsByAttributePath($pattern, $nodeIndex = 0) {
267 DOMIT_DOMException
::raiseException(DOMIT_HIERARCHY_REQUEST_ERR
,
268 ('Method getElementsByAttributePath cannot be called by class ' . get_class($this)));
269 } //getElementsByAttributePath
272 * Adds all child nodes of the specified nodeType to the NodeList
274 * @param Object The NodeList collection
275 * @param string The nodeType of matching nodes
277 function getTypedNodes(&$nodeList, $type) {
278 DOMIT_DOMException
::raiseException(DOMIT_HIERARCHY_REQUEST_ERR
,
279 ('Method getTypedNodes cannot be called by class ' . get_class($this)));
283 * Adds all child nodes of the specified nodeValue to the NodeList
285 * @param Object The NodeList collection
286 * @param string The nodeValue of matching nodes
288 function getValuedNodes(&$nodeList, $value) {
289 DOMIT_DOMException
::raiseException(DOMIT_HIERARCHY_REQUEST_ERR
,
290 ('Method getValuedNodes cannot be called by class ' . get_class($this)));
294 * Returns the concatented text of the current node and its children
295 * @return string The concatented text of the current node and its children
298 return $this->nodeValue
;
302 * Indicates whether the specified feature is supported by the DOM implementation and this node
303 * @param string The feature
304 * @param string The version of the DOM implementation
305 * @return boolean True if the specified feature is supported
307 function isSupported($feature, $version = null) {
308 //don't worry about parsing based on version at this point in time;
309 //the only feature that is supported is 'XML'...
310 if (($version == '1.0') ||
($version == '2.0') ||
($version == null)) {
311 if (strtoupper($feature) == 'XML') {
320 * Formats a string for presentation as HTML
321 * @param string The string to be formatted
322 * @param boolean True if the string is to be sent directly to output
323 * @return string The HTML formatted string
325 function forHTML($str, $doPrint = false) {
326 require_once(DOMIT_INCLUDE_PATH
. 'xml_domit_utilities.php');
327 return DOMIT_Utilities
::forHTML($str, $doPrint);
331 * Generates an array representation of the node and its children
333 * @return Array A representation of the node and its children
336 DOMIT_DOMException
::raiseException(DOMIT_HIERARCHY_REQUEST_ERR
,
337 ('Method toArray cannot be called by class ' . get_class($this)));
341 * A node event that can be set to fire upon document loading, used for node initialization
345 //you can override this method if you subclass any of the
346 //DOMIT_Nodes. It's a way of performing
347 //initialization of your subclass as soon as the document
348 //has been loaded (as opposed to as soon as the current node
349 //has been instantiated).
353 * Clears previousSibling, nextSibling, and parentNode references from a node that has been removed
355 function clearReferences() {
356 if ($this->previousSibling
!= null) {
357 unset($this->previousSibling
);
358 $this->previousSibling
= null;
360 if ($this->nextSibling
!= null) {
361 unset($this->nextSibling
);
362 $this->nextSibling
= null;
364 if ($this->parentNode
!= null) {
365 unset($this->parentNode
);
366 $this->parentNode
= null;
371 * Generates a normalized (formatted for readability) representation of the node and its children
372 * @param boolean True if HTML readable output is desired
373 * @param boolean True if illegal xml characters in text nodes and attributes should be converted to entities
374 * @return string The formatted string representation
376 function toNormalizedString($htmlSafe = false, $subEntities=false) {
377 //require this file for generating a normalized (readable) xml string representation
378 require_once(DOMIT_INCLUDE_PATH
. 'xml_domit_utilities.php');
379 global $DOMIT_defined_entities_flip;
381 $result = DOMIT_Utilities
::toNormalizedString($this, $subEntities, $DOMIT_defined_entities_flip);
383 if ($htmlSafe) $result = $this->forHTML($result);
386 } //toNormalizedString
390 * A parent class for nodes which possess child nodes
392 * @package domit-xmlparser
393 * @subpackage domit-xmlparser-main
394 * @author John Heinstein <johnkarl@nbnet.nb.ca>
396 class DOMIT_ChildNodes_Interface
extends DOMIT_Node
{
398 * Raises error if abstract class is directly instantiated
400 function DOMIT_ChildNodes_Interface() {
401 DOMIT_DOMException
::raiseException(DOMIT_ABSTRACT_CLASS_INSTANTIATION_ERR
,
402 'Cannot instantiate abstract class DOMIT_ChildNodes_Interface');
403 } //DOMIT_ChildNodes_Interface
406 * Appends a node to the childNodes list of the current node
407 * @param Object The node to be appended
408 * @return Object The appended node
410 function &appendChild(&$child) {
411 if ($child->nodeType
== DOMIT_ATTRIBUTE_NODE
) {
412 DOMIT_DOMException
::raiseException(DOMIT_HIERARCHY_REQUEST_ERR
,
413 ('Cannot add a node of type ' . get_class($child) . ' using appendChild'));
415 else if ($child->nodeType
== DOMIT_DOCUMENT_FRAGMENT_NODE
) {
416 $total = $child->childCount
;
418 for ($i = 0; $i < $total; $i++
) {
419 $currChild =& $child->childNodes
[$i];
420 $this->appendChild($currChild);
424 if (!($this->hasChildNodes())) {
425 $this->childNodes
[0] =& $child;
426 $this->firstChild
=& $child;
429 //remove $child if it already exists
430 $index = $this->getChildNodeIndex($this->childNodes
, $child);
433 $this->removeChild($child);
437 $numNodes = $this->childCount
;
438 $prevSibling =& $this->childNodes
[($numNodes - 1)];
440 $this->childNodes
[$numNodes] =& $child;
442 //set next and previous relationships
443 $child->previousSibling
=& $prevSibling;
444 $prevSibling->nextSibling
=& $child;
447 $this->lastChild
=& $child;
448 $child->parentNode
=& $this;
450 unset($child->nextSibling
);
451 $child->nextSibling
= null;
453 $child->setOwnerDocument($this);
461 * Inserts a node to the childNodes list of the current node
462 * @param Object The node to be inserted
463 * @param Object The node before which the insertion is to occur
464 * @return Object The inserted node
466 function &insertBefore(&$newChild, &$refChild) {
467 if ($newChild->nodeType
== DOMIT_ATTRIBUTE_NODE
) {
468 DOMIT_DOMException
::raiseException(DOMIT_HIERARCHY_REQUEST_ERR
,
469 ('Cannot add a node of type ' . get_class($newChild) . ' using insertBefore'));
472 if (($refChild->nodeType
== DOMIT_DOCUMENT_NODE
) ||
473 ($refChild->parentNode
->nodeType
== DOMIT_DOCUMENT_NODE
) ||
474 ($refChild->parentNode
== null)) {
476 DOMIT_DOMException
::raiseException(DOMIT_NOT_FOUND_ERR
,
477 'Reference child not present in the child nodes list.');
480 //if reference child is also the node to be inserted
481 //leave the document as is and don't raise an exception
482 if ($refChild->uid
== $newChild->uid
) {
486 //if $newChild is a DocumentFragment,
487 //loop through and insert each node separately
488 if ($newChild->nodeType
== DOMIT_DOCUMENT_FRAGMENT_NODE
) {
489 $total = $newChild->childCount
;
491 for ($i = 0; $i < $total; $i++
) {
492 $currChild =& $newChild->childNodes
[$i];
493 $this->insertBefore($currChild, $refChild);
499 //remove $newChild if it already exists
500 $index = $this->getChildNodeIndex($this->childNodes
, $newChild);
502 $this->removeChild($newChild);
505 //find index of $refChild in childNodes
506 $index = $this->getChildNodeIndex($this->childNodes
, $refChild);
509 //reset sibling chain
510 if ($refChild->previousSibling
!= null) {
511 $refChild->previousSibling
->nextSibling
=& $newChild;
512 $newChild->previousSibling
=& $refChild->previousSibling
;
515 $this->firstChild
=& $newChild;
517 if ($newChild->previousSibling
!= null) {
518 unset($newChild->previousSibling
);
519 $newChild->previousSibling
= null;
523 $newChild->parentNode
=& $refChild->parentNode
;
524 $newChild->nextSibling
=& $refChild;
525 $refChild->previousSibling
=& $newChild;
527 //add node to childNodes
528 $i = $this->childCount
;
532 $this->childNodes
[$i] =& $this->childNodes
[($i - 1)];
534 else if ($i == $index) {
535 $this->childNodes
[$i] =& $newChild;
543 $this->appendChild($newChild);
546 $newChild->setOwnerDocument($this);
551 * Replaces a node with another
552 * @param Object The new node
553 * @param Object The old node
554 * @return Object The new node
556 function &replaceChild(&$newChild, &$oldChild) {
557 if ($newChild->nodeType
== DOMIT_ATTRIBUTE_NODE
) {
558 DOMIT_DOMException
::raiseException(DOMIT_HIERARCHY_REQUEST_ERR
,
559 ('Cannot add a node of type ' . get_class($newChild) . ' using replaceChild'));
561 else if ($newChild->nodeType
== DOMIT_DOCUMENT_FRAGMENT_NODE
) { //if $newChild is a DocumentFragment
562 //replace the first node then loop through and insert each node separately
563 $total = $newChild->childCount
;
566 $newRef =& $newChild->lastChild
;
567 $this->replaceChild($newRef, $oldChild);
569 for ($i = 0; $i < ($total - 1); $i++
) {
570 $currChild =& $newChild->childNodes
[$i];
571 $this->insertBefore($currChild, $newRef);
578 if ($this->hasChildNodes()) {
579 //remove $newChild if it already exists
580 $index = $this->getChildNodeIndex($this->childNodes
, $newChild);
582 $this->removeChild($newChild);
585 //find index of $oldChild in childNodes
586 $index = $this->getChildNodeIndex($this->childNodes
, $oldChild);
589 $newChild->ownerDocument
=& $oldChild->ownerDocument
;
590 $newChild->parentNode
=& $oldChild->parentNode
;
592 //reset sibling chain
593 if ($oldChild->previousSibling
== null) {
594 unset($newChild->previousSibling
);
595 $newChild->previousSibling
= null;
598 $oldChild->previousSibling
->nextSibling
=& $newChild;
599 $newChild->previousSibling
=& $oldChild->previousSibling
;
602 if ($oldChild->nextSibling
== null) {
603 unset($newChild->nextSibling
);
604 $newChild->nextSibling
= null;
607 $oldChild->nextSibling
->previousSibling
=& $newChild;
608 $newChild->nextSibling
=& $oldChild->nextSibling
;
611 $this->childNodes
[$index] =& $newChild;
613 if ($index == 0) $this->firstChild
=& $newChild;
614 if ($index == ($this->childCount
- 1)) $this->lastChild
=& $newChild;
616 $newChild->setOwnerDocument($this);
621 DOMIT_DOMException
::raiseException(DOMIT_NOT_FOUND_ERR
,
622 ('Reference node for replaceChild not found.'));
627 * Removes a node from the childNodes list of the current node
628 * @param Object The node to be removed
629 * @return Object The removed node
631 function &removeChild(&$oldChild) {
632 if ($this->hasChildNodes()) {
633 //find index of $oldChild in childNodes
634 $index = $this->getChildNodeIndex($this->childNodes
, $oldChild);
637 //reset sibling chain
638 if (($oldChild->previousSibling
!= null) && ($oldChild->nextSibling
!= null)) {
639 $oldChild->previousSibling
->nextSibling
=& $oldChild->nextSibling
;
640 $oldChild->nextSibling
->previousSibling
=& $oldChild->previousSibling
;
642 else if (($oldChild->previousSibling
!= null) && ($oldChild->nextSibling
== null)) {
643 $this->lastChild
=& $oldChild->previousSibling
;
644 unset($oldChild->previousSibling
->nextSibling
);
645 $oldChild->previousSibling
->nextSibling
= null;
647 else if (($oldChild->previousSibling
== null) && ($oldChild->nextSibling
!= null)) {
648 unset($oldChild->nextSibling
->previousSibling
);
649 $oldChild->nextSibling
->previousSibling
= null;
650 $this->firstChild
=& $oldChild->nextSibling
;
652 else if (($oldChild->previousSibling
== null) && ($oldChild->nextSibling
== null)) {
653 unset($this->firstChild
);
654 $this->firstChild
= null;
655 unset($this->lastChild
);
656 $this->lastChild
= null;
659 $total = $this->childCount
;
661 //remove node from childNodes
662 for ($i = 0; $i < $total; $i++
) {
663 if ($i == ($total - 1)) {
664 array_splice($this->childNodes
, $i, 1);
666 else if ($i >= $index) {
667 $this->childNodes
[$i] =& $this->childNodes
[($i +
1)];
673 $oldChild->clearReferences();
678 DOMIT_DOMException
::raiseException(DOMIT_NOT_FOUND_ERR
,
679 ('Target node for removeChild not found.'));
683 * Searches the element tree for an element with the specified attribute name and value.
684 * @param string The value of the attribute
685 * @param string The name of the attribute
686 * @param boolean True if the first found node is to be returned as a node instead of a nodelist
687 * @return object A NodeList of found elements, or null
689 function &getElementsByAttribute($attrName = 'id', $attrValue = '',
690 $returnFirstFoundNode = false) {
691 require_once(DOMIT_INCLUDE_PATH
. 'xml_domit_nodemaps.php');
693 $nodelist =& new DOMIT_NodeList();
695 switch ($this->nodeType
) {
696 case DOMIT_ELEMENT_NODE
:
697 $this->_getElementsByAttribute($nodelist, $attrName = 'id', $attrValue,
698 $returnFirstFoundNode);
701 case DOMIT_DOCUMENT_NODE
:
702 if ($this->documentElement
!= null) {
703 $this->documentElement
->_getElementsByAttribute($nodelist,
704 $attrName, $attrValue, $returnFirstFoundNode);
709 if ($returnFirstFoundNode) {
710 if ($nodelist->getLength() > 0) {
711 return $nodelist->item(0);
720 } //getElementsByAttribute
723 * Searches the element tree for an element with the specified attribute name and value.
724 * @param object The node list of found elements
725 * @param string The value of the attribute
726 * @param string The name of the attribute
727 * @param boolean True if the first found node is to be returned as a node instead of a nodelist
728 * @param boolean True the node has been found
730 function _getElementsByAttribute(&$nodelist, $attrName, $attrValue,
731 $returnFirstFoundNode, $foundNode = false) {
732 if (!($foundNode && $returnFirstFoundNode)) {
733 if ($this->getAttribute($attrName) == $attrValue) {
734 $nodelist->appendNode($this);
736 if ($returnFirstFoundNode) return;
739 $total = $this->childCount
;
741 for ($i = 0; $i < $total; $i++
) {
742 $currNode =& $this->childNodes
[$i];
744 if ($currNode->nodeType
== DOMIT_ELEMENT_NODE
) {
745 $currNode->_getElementsByAttribute($nodelist,
746 $attrName, $attrValue,
747 $returnFirstFoundNode, $foundNode);
752 } //_getElementsByAttribute
753 } //DOMIT_ChildNodes_Interface
756 * A class representing the DOM Document
758 * @package domit-xmlparser
759 * @subpackage domit-xmlparser-main
760 * @author John Heinstein <johnkarl@nbnet.nb.ca>
762 class DOMIT_Document
extends DOMIT_ChildNodes_Interface
{
763 /** @var Object The xml declaration processing instruction */
765 /** @var Object A reference to a DOMIT_DocType object */
767 /** @var Object A reference to the root node of the DOM document */
768 var $documentElement;
769 /** @var string The parser used to process the DOM document, either "EXPAT" or "SAXY" */
771 /** @var Object A reference to the DOMIT_DOMImplementation object */
773 /** @var boolean True if the DOM document has been modifed since being parsed (NOT YET IMPLEMENTED!) */
775 /** @var boolean True if whitespace is to be preserved during parsing (NOT YET IMPLEMENTED!) */
776 var $preserveWhiteSpace = false;
777 /** @var Array User defined translation table for XML entities; passed to SAXY */
778 var $definedEntities = array();
779 /** @var boolean If true, loadXML or parseXML will attempt to detect and repair invalid xml */
780 var $doResolveErrors = false;
781 /** @var boolean If true, elements tags will be rendered to string as <element></element> rather than <element/> */
782 var $doExpandEmptyElementTags = false;
783 /** @var array A list of exceptions to the empty element expansion rule */
784 var $expandEmptyElementExceptions = array();
785 /** @var boolean If true, namespaces will be processed */
786 var $isNamespaceAware = false;
787 /** @var int The error code returned by the SAX parser */
789 /** @var string The error string returned by the SAX parser */
790 var $errorString = '';
791 /** @var object A reference to a http connection or proxy server, if one is required */
792 var $httpConnection = null;
795 * DOM Document constructor
797 function DOMIT_Document() {
798 $this->_constructor();
799 $this->xmlDeclaration
= null;
800 $this->doctype
= null;
801 $this->documentElement
= null;
802 $this->nodeType
= DOMIT_DOCUMENT_NODE
;
803 $this->nodeName
= '#document';
804 $this->ownerDocument
=& $this;
806 $this->implementation
=& new DOMIT_DOMImplementation();
810 * Specifies whether DOMIT! will try to fix invalid XML before parsing begins
811 * @param boolean True if errors are to be resolved
813 function resolveErrors($truthVal) {
814 $this->doResolveErrors
= $truthVal;
818 * Specifies whether DOMIT! processes namespace information
819 * @param boolean True if namespaces are to be processed
821 function setNamespaceAwareness($truthVal) {
822 $this->isNamespaceAware
= $truthVal;
823 } //setNamespaceAwareness
826 * Specifies the parameters of the http conection used to obtain the xml data
827 * @param string The ip address or domain name of the connection
828 * @param string The path of the connection
829 * @param int The port that the connection is listening on
830 * @param int The timeout value for the connection
831 * @param string The user name, if authentication is required
832 * @param string The password, if authentication is required
834 function setConnection($host, $path = '/', $port = 80, $timeout = 0, $user = null, $password = null) {
835 require_once(DOMIT_INCLUDE_PATH
. 'php_http_client_generic.php');
837 $this->httpConnection
=& new php_http_client_generic($host, $path, $port, $timeout, $user, $password);
841 * Specifies basic authentication for an http connection
842 * @param string The user name
843 * @param string The password
845 function setAuthorization($user, $password) {
846 $this->httpConnection
->setAuthorization($user, $password);
850 * Specifies that a proxy is to be used to obtain the xml data
851 * @param string The ip address or domain name of the proxy
852 * @param string The path to the proxy
853 * @param int The port that the proxy is listening on
854 * @param int The timeout value for the connection
855 * @param string The user name, if authentication is required
856 * @param string The password, if authentication is required
858 function setProxyConnection($host, $path = '/', $port = 80, $timeout = 0, $user = null, $password = null) {
859 require_once(DOMIT_INCLUDE_PATH
. 'php_http_proxy.php');
861 $this->httpConnection
=& new php_http_proxy($host, $path, $port, $timeout, $user, $password);
862 } //setProxyConnection
865 * Specifies basic authentication for the proxy
866 * @param string The user name
867 * @param string The password
869 function setProxyAuthorization($user, $password) {
870 $this->httpConnection
->setProxyAuthorization($user, $password);
871 } //setProxyAuthorization
874 * Returns the error code from the underlying SAX parser
875 * @return int The error code
877 function getErrorCode() {
878 return $this->errorCode
;
882 * Returns the error string from the underlying SAX parser
883 * @return string The error string
885 function getErrorString() {
886 return $this->errorString
;
890 * Specifies whether elements tags will be rendered to string as <element></element> rather than <element/>
891 * @param boolean True if the expanded form is to be used
892 * @param mixed An array of tag names that should be excepted from expandEmptyElements rule (optional)
894 function expandEmptyElementTags($truthVal, $expandEmptyElementExceptions = false) {
895 $this->doExpandEmptyElementTags
= $truthVal;
897 if (is_array($expandEmptyElementExceptions)) {
898 $this->expandEmptyElementExceptions
= $expandEmptyElementExceptions;
900 } //expandEmptyElementTags
903 * Set the specified node as document element
904 * @param Object The node that is to become document element
905 * @return Object The new document element
907 function &setDocumentElement(&$node) {
908 if ($node->nodeType
== DOMIT_ELEMENT_NODE
) {
909 if ($this->documentElement
== null) {
910 parent
::appendChild($node);
913 parent
::replaceChild($node, $this->documentElement
);
916 $this->documentElement
=& $node;
919 DOMIT_DOMException
::raiseException(DOMIT_HIERARCHY_REQUEST_ERR
,
920 ('Cannot add a node of type ' . get_class($node) . ' as a Document Element.'));
924 } //setDocumentElement
927 * Appends a node to the childNodes list of the current node
928 * @param Object The node to be appended
929 * @return Object The appended node
931 function &appendChild(&$node) {
932 switch ($node->nodeType
) {
933 case DOMIT_ELEMENT_NODE
:
934 if ($this->documentElement
== null) {
935 parent
::appendChild($node);
936 $this->setDocumentElement($node);
939 //error thrown if documentElement already exists!
940 DOMIT_DOMException
::raiseException(DOMIT_HIERARCHY_REQUEST_ERR
,
941 ('Cannot have more than one root node (documentElement) in a DOMIT_Document.'));
945 case DOMIT_PROCESSING_INSTRUCTION_NODE
:
946 case DOMIT_COMMENT_NODE
:
947 parent
::appendChild($node);
950 case DOMIT_DOCUMENT_TYPE_NODE
:
951 if ($this->doctype
== null) {
952 parent
::appendChild($node);
955 DOMIT_DOMException
::raiseException(DOMIT_HIERARCHY_REQUEST_ERR
,
956 ('Cannot have more than one doctype node in a DOMIT_Document.'));
960 case DOMIT_DOCUMENT_FRAGMENT_NODE
:
961 $total = $node->childCount
;
963 for ($i = 0; $i < $total; $i++
) {
964 $currChild =& $node->childNodes
[$i];
965 $this->appendChild($currChild);
970 DOMIT_DOMException
::raiseException(DOMIT_HIERARCHY_REQUEST_ERR
,
971 ('Cannot add a node of type ' . get_class($node) . ' to a DOMIT_Document.'));
978 * Replaces a node with another
979 * @param Object The new node
980 * @param Object The old node
981 * @return Object The new node
983 function &replaceChild(&$newChild, &$oldChild) {
984 if ($this->nodeType
== DOMIT_DOCUMENT_FRAGMENT_NODE
) {
985 $total = $newChild->childCount
;
988 $newRef =& $newChild->lastChild
;
989 $this->replaceChild($newRef, $oldChild);
991 for ($i = 0; $i < ($total - 1); $i++
) {
992 $currChild =& $newChild->childNodes
[$i];
993 parent
::insertBefore($currChild, $newRef);
998 if (($this->documentElement
!= null) && ($oldChild->uid
== $this->documentElement
->uid
)) {
999 if ($newChild->nodeType
== DOMIT_ELEMENT_NODE
) {
1000 //replace documentElement with new node
1001 $this->setDocumentElement($newChild);
1004 DOMIT_DOMException
::raiseException(DOMIT_HIERARCHY_REQUEST_ERR
,
1005 ('Cannot replace Document Element with a node of class ' . get_class($newChild)));
1009 switch ($newChild->nodeType
) {
1010 case DOMIT_ELEMENT_NODE
:
1011 if ($this->documentElement
!= null) {
1012 DOMIT_DOMException
::raiseException(DOMIT_HIERARCHY_REQUEST_ERR
,
1013 ('Cannot have more than one root node (documentElement) in a DOMIT_Document.'));
1016 parent
::replaceChild($newChild, $oldChild);
1020 case DOMIT_PROCESSING_INSTRUCTION_NODE
:
1021 case DOMIT_COMMENT_NODE
:
1022 parent
::replaceChild($newChild, $oldChild);
1025 case DOMIT_DOCUMENT_TYPE_NODE
:
1026 if ($this->doctype
!= null) {
1027 if ($this->doctype
->uid
== $oldchild->uid
) {
1028 parent
::replaceChild($newChild, $oldChild);
1031 DOMIT_DOMException
::raiseException(DOMIT_HIERARCHY_REQUEST_ERR
,
1032 ('Cannot have more than one doctype node in a DOMIT_Document.'));
1036 parent
::replaceChild($newChild, $oldChild);
1041 DOMIT_DOMException
::raiseException(DOMIT_HIERARCHY_REQUEST_ERR
,
1042 ('Nodes of class ' . get_class($newChild) . ' cannot be children of a DOMIT_Document.'));
1051 * Inserts a node to the childNodes list of the current node
1052 * @param Object The node to be inserted
1053 * @param Object The node before which the insertion is to occur
1054 * @return Object The inserted node
1056 function &insertBefore(&$newChild, &$refChild) {
1057 $type = $newChild->nodeType
;
1059 if ($this->nodeType
== DOMIT_DOCUMENT_FRAGMENT_NODE
) {
1060 $total = $newChild->childCount
;
1062 for ($i = 0; $i < $total; $i++
) {
1063 $currChild =& $newChild->childNodes
[$i];
1064 $this->insertBefore($currChild, $refChild);
1067 else if ($type == DOMIT_ELEMENT_NODE
) {
1068 if ($this->documentElement
== null) {
1069 parent
::insertBefore($newChild);
1070 $this->setDocumentElement($newChild);
1073 //error thrown if documentElement already exists!
1074 DOMIT_DOMException
::raiseException(DOMIT_HIERARCHY_REQUEST_ERR
,
1075 ('Cannot have more than one root node (documentElement) in a DOMIT_Document.'));
1078 else if ($type == DOMIT_PROCESSING_INSTRUCTION_NODE
) {
1079 parent
::insertBefore($newChild);
1081 else if ($type == DOMIT_DOCUMENT_TYPE_NODE
) {
1082 if ($this->doctype
== null) {
1083 parent
::insertBefore($newChild);
1086 DOMIT_DOMException
::raiseException(DOMIT_HIERARCHY_REQUEST_ERR
,
1087 ('Cannot have more than one doctype node in a DOMIT_Document.'));
1091 DOMIT_DOMException
::raiseException(DOMIT_HIERARCHY_REQUEST_ERR
,
1092 ('Cannot insert a node of type ' . get_class($newChild) . ' to a DOMIT_Document.'));
1099 * Removes a node from the childNodes list of the current node
1100 * @param Object The node to be removed
1101 * @return Object The removed node
1103 function &removeChild(&$oldChild) {
1104 if ($this->nodeType
== DOMIT_DOCUMENT_FRAGMENT_NODE
) {
1105 $total = $oldChild->childCount
;
1107 for ($i = 0; $i < $total; $i++
) {
1108 $currChild =& $oldChild->childNodes
[$i];
1109 $this->removeChild($currChild);
1113 if (($this->documentElement
!= null) && ($oldChild->uid
== $this->documentElement
->uid
)) {
1114 parent
::removeChild($oldChild);
1115 $this->documentElement
= null;
1118 parent
::removeChild($oldChild);
1122 $oldChild->clearReferences();
1127 * Imports a node from another document to this document (not yet implemented)
1128 * @param Object The node to import
1129 * @param boolean True if a child nodes of the imported node are to be included in the import
1130 * @return Object The imported node
1132 function &importNode(&$importedNode, $deep = true) {
1133 //not yet implemented
1134 DOMIT_DOMException
::raiseException(DOMIT_NOT_SUPPORTED_ERROR
,
1135 ('Method importNode is not yet implemented.'));
1139 * Creates a new DOMIT_DocumentFragment node
1140 * @return Object The new document fragment node
1142 function &createDocumentFragment() {
1143 $node =& new DOMIT_DocumentFragment();
1144 $node->ownerDocument
=& $this;
1147 } //createDocumentFragment
1150 * Creates a new DOMIT_Attr node
1151 * @param string The name of the attribute
1152 * @return Object The new attribute node
1154 function &createAttribute($name) {
1155 $node =& new DOMIT_Attr($name);
1161 * Creates a new DOMIT_Attr node (namespace aware)
1162 * @param string The namespaceURI of the attribute
1163 * @param string The qualifiedName of the attribute
1164 * @return Object The new attribute node
1166 function &createAttributeNS($namespaceURI, $qualifiedName) {
1167 $node =& new DOMIT_Attr($qualifiedName);
1168 $node->namespaceURI
= $namespaceURI;
1170 $colonIndex = strpos($qualifiedName, ":");
1172 if ($colonIndex !== false) {
1173 $node->prefix
= substr($qualifiedName, 0, $colonIndex);
1174 $node->localName
= substr($qualifiedName, ($colonIndex +
1));
1178 $node->localName
= $qualifiedName;
1182 } //createAttributeNS
1185 * Creates a new DOMIT_Element node
1186 * @param string The tag name of the element
1187 * @return Object The new element
1189 function &createElement($tagName) {
1190 $node =& new DOMIT_Element($tagName);
1191 $node->ownerDocument
=& $this;
1197 * Creates a new DOMIT_Element node (namespace aware)
1198 * @param string The namespaceURI of the element
1199 * @param string The qualifiedName of the element
1200 * @return Object The new element
1202 function &createElementNS($namespaceURI, $qualifiedName) {
1203 $node =& new DOMIT_Element($qualifiedName);
1205 $colonIndex = strpos($qualifiedName, ":");
1207 if ($colonIndex !== false) {
1208 $node->prefix
= substr($qualifiedName, 0, $colonIndex);
1209 $node->localName
= substr($qualifiedName, ($colonIndex +
1));
1213 $node->localName
= $qualifiedName;
1216 $node->namespaceURI
= $namespaceURI;
1218 $node->ownerDocument
=& $this;
1224 * Creates a new DOMIT_Text node
1225 * @param string The text of the node
1226 * @return Object The new text node
1228 function &createTextNode($data) {
1229 $node =& new DOMIT_TextNode($data);
1230 $node->ownerDocument
=& $this;
1236 * Creates a new DOMIT_CDataSection node
1237 * @param string The text of the CDATASection
1238 * @return Object The new CDATASection node
1240 function &createCDATASection($data) {
1241 $node =& new DOMIT_CDATASection($data);
1242 $node->ownerDocument
=& $this;
1245 } //createCDATASection
1248 * Creates a new DOMIT_Comment node
1249 * @param string The comment text
1250 * @return Object The new comment node
1252 function &createComment($text) {
1253 $node =& new DOMIT_Comment($text);
1254 $node->ownerDocument
=& $this;
1260 * Creates a new DOMIT_ProcessingInstruction node
1261 * @param string The target of the processing instruction
1262 * @param string The data of the processing instruction
1263 * @return Object The new processing instruction node
1265 function &createProcessingInstruction($target, $data) {
1266 $node =& new DOMIT_ProcessingInstruction($target, $data);
1267 $node->ownerDocument
=& $this;
1270 } //createProcessingInstruction
1273 * Retrieves a NodeList of child elements with the specified tag name
1274 * @param string The matching element tag name
1275 * @return Object A NodeList of found elements
1277 function &getElementsByTagName($tagName) {
1278 $nodeList =& new DOMIT_NodeList();
1280 if ($this->documentElement
!= null) {
1281 $this->documentElement
->getNamedElements($nodeList, $tagName);
1285 } //getElementsByTagName
1288 * Retrieves a NodeList of child elements with the specified namespaceURI and localName
1289 * @param string The matching namespaceURI
1290 * @param string The matching localName
1291 * @return Object A NodeList of found elements
1293 function &getElementsByTagNameNS($namespaceURI, $localName) {
1294 $nodeList =& new DOMIT_NodeList();
1296 if ($this->documentElement
!= null) {
1297 $this->documentElement
->getNamedElementsNS($nodeList, $namespaceURI, $localName);
1301 } //getElementsByTagNameNS
1304 * Returns the element whose ID is given by elementId.
1305 * @param string The id of the matching element
1306 * @param boolean True if XML spec is to be strictly adhered to (only attributes xml:id are considered valid)
1307 * @return Object The found element or null
1309 function &getElementByID($elementID, $isStrict = true) {
1310 if ($this->isNamespaceAware
) {
1311 if ($this->documentElement
!= null) {
1312 $targetAttrNode =& $this->documentElement
->_getElementByID($elementID, $isStrict);
1313 return $targetAttrNode->ownerElement
;
1319 DOMIT_DOMException
::raiseException(DOMIT_INVALID_ACCESS_ERR
,
1320 'Namespace awareness must be enabled to use method getElementByID');
1325 * Retrieves an element or DOMIT_NodeList of elements corresponding to an Xpath-like expression.
1326 * @param string The query pattern
1327 * @param int If a single node is to be returned (rather than the entire NodeList) the index of that node
1328 * @return mixed A NodeList or single node that matches the pattern
1330 function &getElementsByPath($pattern, $nodeIndex = 0) {
1331 require_once(DOMIT_INCLUDE_PATH
. 'xml_domit_getelementsbypath.php');
1333 $gebp = new DOMIT_GetElementsByPath();
1334 $myResponse =& $gebp->parsePattern($this, $pattern, $nodeIndex);
1337 } //getElementsByPath
1340 * Retrieves an element or DOMIT_NodeList of elements corresponding to an Xpath-like attribute expression (NOT YET IMPLEMENTED!)
1341 * @param string The query pattern
1342 * @param int If a single node is to be returned (rather than the entire NodeList) the index of that node
1343 * @return mixed A NodeList or single node that matches the pattern
1345 function &getElementsByAttributePath($pattern, $nodeIndex = 0) {
1346 require_once(DOMIT_INCLUDE_PATH
. 'xml_domit_getelementsbypath.php');
1348 $gabp = new DOMIT_GetElementsByAttributePath();
1349 $myResponse =& $gabp->parsePattern($this, $pattern, $nodeIndex);
1352 } //getElementsByAttributePath
1355 * Retrieves all child nodes of the specified nodeType
1356 * @param string The nodeType of matching nodes
1357 * @param Object The root node of the search
1358 * @return Object A NodeList containing found nodes
1360 function &getNodesByNodeType($type, &$contextNode) {
1361 $nodeList =& new DOMIT_NodeList();
1363 if (($type == DOMIT_DOCUMENT_NODE
) ||
($contextNode->nodeType
== DOMIT_DOCUMENT_NODE
)){
1364 $nodeList->appendNode($this);
1366 else if ($contextNode->nodeType
== DOMIT_ELEMENT_NODE
) {
1367 $contextNode->getTypedNodes($nodeList, $type);
1369 else if ($contextNode->uid
== $this->uid
) {
1370 if ($this->documentElement
!= null) {
1371 if ($type == DOMIT_ELEMENT_NODE
) {
1372 $nodeList->appendNode($this->documentElement
);
1375 $this->documentElement
->getTypedNodes($nodeList, $type);
1380 } //getNodesByNodeType
1383 * Retrieves all child nodes of the specified nodeValue
1384 * @param string The nodeValue of matching nodes
1385 * @param Object The root node of the search
1386 * @return Object A NodeList containing found nodes
1388 function &getNodesByNodeValue($value, &$contextNode) {
1389 $nodeList =& new DOMIT_NodeList();
1391 if ($contextNode->uid
== $this->uid
) {
1392 if ($this->nodeValue
== $value) {
1393 $nodeList->appendNode($this);
1397 if ($this->documentElement
!= null) {
1398 $this->documentElement
->getValuedNodes($nodeList, $value);
1402 } //getNodesByNodeValue
1405 * Parses an xml string
1406 * @param string The xml text to be parsed
1407 * @param boolean True if SAXY is to be used instead of Expat
1408 * @param boolean False if CDATA Section are to be generated as Text nodes
1409 * @param boolean True if onLoad is to be called on each node after parsing
1410 * @return boolean True if parsing is successful
1412 function parseXML($xmlText, $useSAXY = true, $preserveCDATA = true, $fireLoadEvent = false) {
1413 require_once(DOMIT_INCLUDE_PATH
. 'xml_domit_utilities.php');
1415 if ($this->doResolveErrors
) {
1416 require_once(DOMIT_INCLUDE_PATH
. 'xml_domit_doctor.php');
1417 $xmlText = DOMIT_Doctor
::fixAmpersands($xmlText);
1420 if (DOMIT_Utilities
::validateXML($xmlText)) {
1421 $domParser =& new DOMIT_Parser();
1423 if ($useSAXY ||
(!function_exists('xml_parser_create'))) {
1424 //use SAXY parser to populate xml tree
1425 $this->parser
= 'SAXY';
1426 $success = $domParser->parseSAXY($this, $xmlText, $preserveCDATA, $this->definedEntities
);
1429 //use Expat parser to populate xml tree
1430 $this->parser
= 'EXPAT';
1431 $success = $domParser->parse($this, $xmlText, $preserveCDATA);
1434 if ($fireLoadEvent && ($this->documentElement
!= null)) $this->load($this->documentElement
);
1444 * Parses an xml file
1445 * @param string The xml file to be parsed
1446 * @param boolean True if SAXY is to be used instead of Expat
1447 * @param boolean False if CDATA Section are to be generated as Text nodes
1448 * @param boolean True if onLoad is to be called on each node after parsing
1449 * @return boolean True if parsing is successful
1451 function loadXML($filename, $useSAXY = true, $preserveCDATA = true, $fireLoadEvent = false) {
1452 $xmlText = $this->getTextFromFile($filename);
1454 return $this->parseXML($xmlText, $useSAXY, $preserveCDATA, $fireLoadEvent);
1458 * Retrieves text from a file
1459 * @param string The file path
1460 * @return string The text contained in the file
1462 function getTextFromFile($filename) {
1463 if ($this->httpConnection
!= null) {
1464 $response =& $this->httpConnection
->get($filename);
1466 $this->httpConnection
->disconnect();
1467 return $response->getResponse();
1469 else if (function_exists('file_get_contents')) {
1470 //if (file_exists($filename)) {
1471 return file_get_contents($filename);
1475 require_once(DOMIT_INCLUDE_PATH
. 'php_file_utilities.php');
1477 $fileContents =& php_file_utilities
::getDataFromFile($filename, 'r');
1478 return $fileContents;
1485 * Saves the current DOM document as an xml file
1486 * @param string The path of the xml file
1487 * @param boolean True if xml text is to be normalized before saving
1488 * @return boolean True if save is successful
1490 function saveXML($filename, $normalized=false) {
1492 $stringRep = $this->toNormalizedString(false, true);
1495 $stringRep = $this->toString(false, true);
1498 return $this->saveTextToFile($filename, $stringRep);
1502 * Saves text to a file
1503 * @param string The file path
1504 * @param string The text to be saved
1505 * @return boolean True if the save is successful
1507 function saveTextToFile($filename, $text) {
1508 if (function_exists('file_put_contents')) {
1509 file_put_contents($filename, $text);
1512 require_once(DOMIT_INCLUDE_PATH
. 'php_file_utilities.php');
1513 php_file_utilities
::putDataToFile($filename, $text, 'w');
1516 return (file_exists($filename) && is_writable($filename));
1520 * Indicates the SAX parser used to parse the current document
1521 * @return string Either "SAXY" or "EXPAT"
1523 function parsedBy() {
1524 return $this->parser
;
1528 * Returns the concatented text of the current node and its children
1529 * @return string The concatented text of the current node and its children
1531 function getText() {
1532 if ($this->documentElement
!= null) {
1533 $root =& $this->documentElement
;
1534 return $root->getText();
1541 * Returns a doctype object
1542 * @return mixed The doctype object, or null if none exists
1544 function getDocType() {
1545 return $this->doctype
;
1549 * Returns the xml declaration processing instruction
1550 * @return mixed The xml declaration processing instruction, or null if none exists
1552 function getXMLDeclaration() {
1553 return $this->xmlDeclaration
;
1554 } //getXMLDeclaration
1557 * Returns a reference to the DOMIT_DOMImplementation object
1558 * @return Object A reference to the DOMIT_DOMImplementation object
1560 function &getDOMImplementation() {
1561 return $this->implementation
;
1562 } //getDOMImplementation
1565 * Manages the firing of the onLoad() event
1566 * @param Object The parent node of the current recursion
1568 function load(&$contextNode) {
1569 $total = $contextNode->childCount
;
1571 for ($i = 0; $i < $total; $i++
) {
1572 $currNode =& $contextNode->childNodes
[$i];
1573 $currNode->ownerDocument
->load($currNode);
1576 $contextNode->onLoad();
1580 * Returns the current version of DOMIT!
1581 * @return Object The current version of DOMIT!
1583 function getVersion() {
1584 return DOMIT_VERSION
;
1588 * Appends an array of entity mappings to the existing translation table
1590 * Intended mainly to facilitate the conversion of non-ASCII entities into equivalent characters
1592 * @param array A list of entity mappings in the format: array('&' => '&');
1594 function appendEntityTranslationTable($table) {
1595 $this->definedEntities
= $table;
1597 global $DOMIT_defined_entities_flip;
1598 $DOMIT_defined_entities_flip = array_flip($table);
1599 } //appendEntityTranslationTable
1602 * Generates an array representation of the node and its children
1603 * @return Array A representation of the node and its children
1605 function toArray() {
1606 $arReturn = array($this->nodeName
=> array());
1607 $total = $this->childCount
;
1609 for ($i = 0; $i < $total; $i++
) {
1610 $arReturn[$this->nodeName
][$i] = $this->childNodes
[$i]->toArray();
1617 * Copies a node and/or its children
1618 * @param boolean True if all child nodes are also to be cloned
1619 * @return Object A copy of the node and/or its children
1621 function &cloneNode($deep = false) {
1622 $className = get_class($this);
1623 $clone =& new $className($this->nodeName
);
1626 $total = $this->childCount
;
1628 for ($i = 0; $i < $total; $i++
) {
1629 $currentChild =& $this->childNodes
[$i];
1630 $clone->appendChild($currentChild->cloneNode($deep));
1632 if ($currentChild->nodeType
== DOMIT_DOCUMENT_TYPE_NODE
) {
1633 $clone->doctype
=& $clone->childNodes
[$i];
1636 if (($currentChild->nodeType
== DOMIT_PROCESSING_INSTRUCTION_NODE
) &&
1637 ($currentChild->getTarget() == 'xml')) {
1638 $clone->xmlDeclaration
=& $clone->childNodes
[$i];
1647 * Generates a string representation of the node and its children
1648 * @param boolean True if HTML readable output is desired
1649 * @param boolean True if illegal xml characters in text nodes and attributes should be converted to entities
1650 * @return string The string representation
1652 function toString($htmlSafe = false, $subEntities=false) {
1654 $total = $this->childCount
;
1656 for ($i = 0; $i < $total; $i++
) {
1657 $result .= $this->childNodes
[$i]->toString(false, $subEntities);
1660 if ($htmlSafe) $result = $this->forHTML($result);
1667 * A class representing the DOM Element
1669 * @package domit-xmlparser
1670 * @subpackage domit-xmlparser-main
1671 * @author John Heinstein <johnkarl@nbnet.nb.ca>
1673 class DOMIT_Element
extends DOMIT_ChildNodes_Interface
{
1675 * DOM Element constructor
1676 * @param string The tag name of the element
1678 function DOMIT_Element($tagName) {
1679 $this->_constructor();
1680 $this->nodeType
= DOMIT_ELEMENT_NODE
;
1681 $this->nodeName
= $tagName;
1682 $this->attributes
= new DOMIT_NamedNodeMap_Attr();
1683 $this->childNodes
= array();
1687 * Returns the tag name of the element
1688 * @return string The tag name of the element
1690 function getTagName() {
1691 return $this->nodeName
;
1695 * Adds elements with the specified tag name to a NodeList collection
1696 * @param Object The NodeList collection
1697 * @param string The tag name of matching elements
1699 function getNamedElements(&$nodeList, $tagName) {
1700 if (($this->nodeName
== $tagName) ||
($tagName == '*')) {
1701 $nodeList->appendNode($this);
1704 $total = $this->childCount
;
1706 for ($i = 0; $i < $total; $i++
) {
1707 $this->childNodes
[$i]->getNamedElements($nodeList, $tagName);
1709 } //getNamedElements
1712 * Adds elements with the specified tag name to a NodeList collection
1713 * @param Object The NodeList collection
1714 * @param string The namespaceURI of matching elements
1715 * @param string The localName of matching elements
1717 function getNamedElementsNS(&$nodeList, $namespaceURI, $localName) {
1718 if ((($namespaceURI == $this->namespaceURI
) ||
($namespaceURI == '*')) &&
1719 (($localName == $this->localName
) ||
($localName == '*'))) {
1720 $nodeList->appendNode($this);
1723 $total = $this->childCount
;
1725 for ($i = 0; $i < $total; $i++
) {
1726 if ($this->childNodes
[$i]->nodeType
== DOMIT_ELEMENT_NODE
) {
1727 $this->childNodes
[$i]->getNamedElementsNS($nodeList, $namespaceURI, $localName);
1730 } //getNamedElementsNS
1733 * Returns the concatented text of the current node and its children
1734 * @return string The concatented text of the current node and its children
1736 function getText() {
1738 $numChildren = $this->childCount
;
1740 for ($i = 0; $i < $numChildren; $i++
) {
1741 $child =& $this->childNodes
[$i];
1742 $text .= $child->getText();
1749 * If a child text node exists, sets the nodeValue to $data. A child text node is created if none exists
1750 * @param string The text data of the node
1752 function setText($data) {
1753 switch ($this->childCount
) {
1755 if ($this->firstChild
->nodeType
== DOMIT_TEXT_NODE
) {
1756 $this->firstChild
->setText($data);
1761 $childTextNode =& $this->ownerDocument
->createTextNode($data);
1762 $this->appendChild($childTextNode);
1766 //do nothing. Maybe throw error???
1771 * Retrieves a NodeList of child elements with the specified tag name
1772 * @param string The matching element tag name
1773 * @return Object A NodeList of found elements
1775 function &getElementsByTagName($tagName) {
1776 $nodeList =& new DOMIT_NodeList();
1777 $this->getNamedElements($nodeList, $tagName);
1780 } //getElementsByTagName
1783 * Retrieves a NodeList of child elements with the specified namespaceURI and localName
1784 * @param string The namespaceURI
1785 * @param string The localName
1786 * @return Object A NodeList of found elements
1788 function &getElementsByTagNameNS($namespaceURI, $localName) {
1789 $nodeList =& new DOMIT_NodeList();
1790 $this->getNamedElementsNS($nodeList, $namespaceURI, $localName);
1793 } //getElementsByTagNameNS
1796 * Returns the attribute node whose ID is given by elementId.
1797 * @param string The id of the matching element
1798 * @param boolean True if XML spec is to be strictly adhered to (only attributes xml:id are considered valid)
1799 * @return Object The found attribute or null
1801 function &_getElementByID($elementID, $isStrict) {
1803 $myAttrNode =& $this->getAttributeNodeNS(DOMIT_XML_NAMESPACE
, 'id');
1804 if (($myAttrNode != null)&& ($myAttrNode->getValue() == $elementID)) return $myAttrNode;
1807 $myAttrNode =& $this->getAttributeNodeNS('', 'ID');
1808 if (($myAttrNode != null)&& ($myAttrNode->getValue() == $elementID)) return $myAttrNode;
1810 $myAttrNode =& $this->getAttributeNodeNS('', 'id');
1811 if (($myAttrNode != null)&& ($myAttrNode->getValue() == $elementID)) return $myAttrNode;
1814 $total = $this->childCount
;
1816 for ($i = 0; $i < $total; $i++
) {
1817 if ($this->childNodes
[$i]->nodeType
== DOMIT_ELEMENT_NODE
) {
1818 $foundNode =& $this->childNodes
[$i]->_getElementByID($elementID, $isStrict);
1820 if ($foundNode != null) {
1830 * Retrieves an element or DOMIT_NodeList of elements corresponding to an Xpath-like expression.
1831 * @param string The query pattern
1832 * @param int If a single node is to be returned (rather than the entire NodeList) the index of that node
1833 * @return mixed A NodeList or single node that matches the pattern
1835 function &getElementsByPath($pattern, $nodeIndex = 0) {
1836 require_once(DOMIT_INCLUDE_PATH
. 'xml_domit_getelementsbypath.php');
1838 $gebp = new DOMIT_GetElementsByPath();
1839 $myResponse =& $gebp->parsePattern($this, $pattern, $nodeIndex);
1842 } //getElementsByPath
1845 * Retrieves an element or DOMIT_NodeList of elements corresponding to an Xpath-like attribute expression (NOT YET IMPLEMENTED!)
1846 * @param string The query pattern
1847 * @param int If a single node is to be returned (rather than the entire NodeList) the index of that node
1848 * @return mixed A NodeList or single node that matches the pattern
1850 function &getElementsByAttributePath($pattern, $nodeIndex = 0) {
1851 require_once(DOMIT_INCLUDE_PATH
. 'xml_domit_getelementsbypath.php');
1853 $gabp = new DOMIT_GetElementsByAttributePath();
1854 $myResponse =& $gabp->parsePattern($this, $pattern, $nodeIndex);
1857 } //getElementsByAttributePath
1860 * Adds all child nodes of the specified nodeType to the NodeList
1861 * @param Object The NodeList collection
1862 * @param string The nodeType of matching nodes
1864 function getTypedNodes(&$nodeList, $type) {
1865 $numChildren = $this->childCount
;
1867 for ($i = 0; $i < $numChildren; $i++
) {
1868 $child =& $this->childNodes
[$i];
1870 if ($child->nodeType
== $type) {
1871 $nodeList->appendNode($child);
1874 if ($child->hasChildNodes()) {
1875 $child->getTypedNodes($nodeList, $type);
1881 * Adds all child nodes of the specified nodeValue to the NodeList
1882 * @param Object The NodeList collection
1883 * @param string The nodeValue of matching nodes
1885 function getValuedNodes(&$nodeList, $value) {
1886 $numChildren = $this->childCount
;
1888 for ($i = 0; $i < $numChildren; $i++
) {
1889 $child =& $this->childNodes
[$i];
1891 if ($child->nodeValue
== $value) {
1892 $nodeList->appendNode($child);
1895 if ($child->hasChildNodes()) {
1896 $child->getValuedNodes($nodeList, $value);
1902 * Gets the value of the specified attribute, if it exists
1903 * @param string The attribute name
1904 * @return string The attribute value
1906 function getAttribute($name) {
1907 $returnNode =& $this->attributes
->getNamedItem($name);
1909 if ($returnNode == null) {
1913 return $returnNode->getValue();
1918 * Gets the value of the attribute with the specified namespaceURI and localName, if it exists
1919 * @param string The namespaceURI
1920 * @param string The localName
1921 * @return string The attribute value
1923 function getAttributeNS($namespaceURI, $localName) {
1924 $returnNode =& $this->attributes
->getNamedItemNS($namespaceURI, $localName);
1926 if ($returnNode == null) {
1930 return $returnNode->getValue();
1935 * Sets the value of the specified attribute; creates a new attribute if one doesn't exist
1936 * @param string The attribute name
1937 * @param string The desired attribute value
1939 function setAttribute($name, $value) {
1940 $returnNode =& $this->attributes
->getNamedItem($name);
1942 if ($returnNode == null) {
1943 $newAttr =& new DOMIT_Attr($name);
1944 $newAttr->setValue($value);
1945 $this->attributes
->setNamedItem($newAttr);
1948 $returnNode->setValue($value);
1953 * Sets the value of the specified attribute; creates a new attribute if one doesn't exist
1954 * @param string The attribute namespaceURI
1955 * @param string The attribute qualifiedName
1956 * @param string The desired attribute value
1958 function setAttributeNS($namespaceURI, $qualifiedName, $value) {
1960 $colonIndex = strpos($qualifiedName, ":");
1962 if ($colonIndex !== false) {
1963 $localName = substr($qualifiedName, ($colonIndex +
1));
1966 $localName = $qualifiedName;
1969 $returnNode =& $this->attributes
->getNamedItemNS($namespaceURI, $localName);
1971 if ($returnNode == null) {
1972 //create this manually in case element has no ownerDocument to reference
1973 $newAttr =& new DOMIT_Attr($qualifiedName);
1974 $newAttr->prefix
= substr($qualifiedName, 0, $colonIndex);
1975 $newAttr->localName
= $localName;
1976 $newAttr->namespaceURI
= $namespaceURI;
1978 $newAttr->setValue($value);
1979 $this->attributes
->setNamedItemNS($newAttr);
1980 $newAttr->ownerElement
=& $this;
1983 $returnNode->setValue($value);
1988 * Removes the specified attribute
1989 * @param string The name of the attribute to be removed
1991 function removeAttribute($name) {
1992 $returnNode =& $this->attributes
->removeNamedItem($name);
1996 * Removes the specified attribute
1997 * @param string The namespaceURI of the attribute to be removed
1998 * @param string The localName of the attribute to be removed
2000 function removeAttributeNS($namespaceURI, $localName) {
2001 $returnNode =& $this->attributes
->removeNamedItemNS($namespaceURI, $localName);
2002 unset($returnNode->ownerElement
);
2003 $returnNode->ownerElement
= null;
2004 } //removeAttributeNS
2007 * Determines whether an attribute with the specified name exists
2008 * @param string The name of the attribute
2009 * @return boolean True if the attribute exists
2011 function hasAttribute($name) {
2012 $returnNode =& $this->attributes
->getNamedItem($name);
2014 return ($returnNode != null);
2018 * Determines whether an attribute with the specified namespaceURI and localName exists
2019 * @param string The namespaceURI of the attribute
2020 * @param string The localName of the attribute
2021 * @return boolean True if the attribute exists
2023 function hasAttributeNS($namespaceURI, $localName) {
2024 $returnNode =& $this->attributes
->getNamedItemNS($namespaceURI, $localName);
2026 return ($returnNode != null);
2030 * Determines whether the element has any atributes
2031 * @return boolean True if the element has any atributes
2033 function hasAttributes() {
2034 return ($this->attributes
->getLength() > 0);
2038 * Gets a reference to the specified attribute node
2039 * @param string The attribute name
2040 * @return Object A reference to the found node, or null
2042 function &getAttributeNode($name) {
2043 $returnNode =& $this->attributes
->getNamedItem($name);
2045 } //getAttributeNode
2048 * Gets a reference to the specified attribute node
2049 * @param string The attribute namespaceURI
2050 * @param string The attribute localName
2051 * @return Object A reference to the found node, or null
2053 function &getAttributeNodeNS($namespaceURI, $localName) {
2054 $returnNode =& $this->attributes
->getNamedItemNS($namespaceURI, $localName);
2056 } //getAttributeNodeNS
2059 * Adds an attribute node to the current element
2060 * @param Object The attribute node to be added
2061 * @return Object A reference to the newly added node
2063 function &setAttributeNode(&$newAttr) {
2064 $returnNode =& $this->attributes
->setNamedItem($newAttr);
2066 } //setAttributeNode
2069 * Adds an attribute node to the current element (namespace aware)
2070 * @param Object The attribute node to be added
2071 * @return Object A reference to the newly added node
2073 function &setAttributeNodeNS(&$newAttr) {
2074 $returnNode =& $this->attributes
->setNamedItemNS($newAttr);
2075 $newAttr->ownerElement
=& $this;
2077 } //setAttributeNodeNS
2080 * Removes an attribute node from the current element
2081 * @param Object The attribute node to be removed
2082 * @return Object A reference to the removed node
2084 function &removeAttributeNode(&$oldAttr) {
2085 $attrName = $oldAttr->getName();
2086 $returnNode =& $this->attributes
->removeNamedItem($attrName);
2088 if ($returnNode == null) {
2089 DOMIT_DOMException
::raiseException(DOMIT_NOT_FOUND_ERR
,
2090 'Target attribute not found.');
2095 } //removeAttributeNode
2098 * Collapses adjacent text nodes in entire element subtree
2100 function normalize() {
2101 if ($this->hasChildNodes()) {
2102 $currNode =& $this->childNodes
[0];
2104 while ($currNode->nextSibling
!= null) {
2105 $nextNode =& $currNode->nextSibling
;
2107 if (($currNode->nodeType
== DOMIT_TEXT_NODE
) &&
2108 ($nextNode->nodeType
== DOMIT_TEXT_NODE
)) {
2110 $currNode->nodeValue
.= $nextNode->nodeValue
;
2111 $this->removeChild($nextNode);
2114 $currNode->normalize();
2117 if ($currNode->nextSibling
!= null) {
2118 $currNode =& $currNode->nextSibling
;
2125 * Generates an array representation of the node and its children
2126 * @return Array A representation of the node and its children
2128 function toArray() {
2129 $arReturn = array($this->nodeName
=> array("attributes" => $this->attributes
->toArray()));
2130 $total = $this->childCount
;
2132 for ($i = 0; $i < $total; $i++
) {
2133 $arReturn[$this->nodeName
][$i] = $this->childNodes
[$i]->toArray();
2140 * Copies a node and/or its children
2141 * @param boolean True if all child nodes are also to be cloned
2142 * @return Object A copy of the node and/or its children
2144 function &cloneNode($deep = false) {
2145 $className = get_class($this);
2146 $clone =& new $className($this->nodeName
);
2148 $clone->attributes
=& $this->attributes
->createClone($deep);
2151 $total = $this->childCount
;
2153 for ($i = 0; $i < $total; $i++
) {
2154 $currentChild =& $this->childNodes
[$i];
2155 $clone->appendChild($currentChild->cloneNode($deep));
2163 * Generates a string representation of the node and its children
2164 * @param boolean True if HTML readable output is desired
2165 * @param boolean True if illegal xml characters in text nodes and attributes should be converted to entities
2166 * @return string The string representation
2168 function toString($htmlSafe = false, $subEntities=false) {
2169 $result = '<' . $this->nodeName
;
2170 $result .= $this->attributes
->toString(false, $subEntities);
2173 $myNodes =& $this->childNodes
;
2174 $total = count($myNodes);
2179 for ($i = 0; $i < $total; $i++
) {
2180 $child =& $myNodes[$i];
2181 $result .= $child->toString(false, $subEntities);
2184 $result .= '</' . $this->nodeName
. '>';
2187 if ($this->ownerDocument
->doExpandEmptyElementTags
) {
2188 if (in_array($this->nodeName
, $this->ownerDocument
->expandEmptyElementExceptions
)) {
2192 $result .= '></' . $this->nodeName
. '>';
2196 if (in_array($this->nodeName
, $this->ownerDocument
->expandEmptyElementExceptions
)) {
2197 $result .= '></' . $this->nodeName
. '>';
2205 if ($htmlSafe) $result = $this->forHTML($result);
2212 * A parent class for Text and CDATA Section nodes
2214 * @package domit-xmlparser
2215 * @subpackage domit-xmlparser-main
2216 * @author John Heinstein <johnkarl@nbnet.nb.ca>
2218 class DOMIT_CharacterData
extends DOMIT_Node
{
2220 * Prevents direct instantiation of DOMIT_CharacterData class
2223 function DOMIT_CharacterData() {
2224 DOMIT_DOMException
::raiseException(DOMIT_ABSTRACT_CLASS_INSTANTIATION_ERR
,
2225 'Cannot instantiate abstract class DOMIT_CharacterData');
2226 } //DOMIT_CharacterData
2229 * Gets the node value of the current text node
2230 * @return string The node value of the current text node
2232 function getData() {
2233 return $this->nodeValue
;
2237 * Gets the length of the text in the current node
2238 * @return int The length of the text in the current node
2240 function getLength() {
2241 return strlen($this->nodeValue
);
2245 * Gets a subset of the current node text
2246 * @param int The starting point of the substring
2247 * @param int The length of the substring
2248 * @return string The subset of the current node text
2250 function substringData($offset, $count) {
2251 $totalChars = $this->getLength();
2253 if (($offset < 0) ||
(($offset +
$count) > $totalChars)) {
2255 DOMIT_DOMException
::raiseException(DOMIT_INDEX_SIZE_ERR
,
2256 'Character Data index out of bounds.');
2260 $data = $this->getData();
2261 return substr($data, $offset, $count);
2266 * Appends the specified text to the current node text
2267 * @param string The text to be appended
2269 function appendData($arg) {
2270 $this->setText($this->nodeValue
. $arg);
2274 * Inserts text at the sepecified offset
2275 * @param int The insertion point
2276 * @param string The text to be inserted
2278 function insertData($offset, $arg) {
2279 $totalChars = $this->getLength();
2281 if (($offset < 0) ||
($offset > $totalChars)) {
2283 DOMIT_DOMException
::raiseException(DOMIT_INDEX_SIZE_ERR
,
2284 'Character Data index out of bounds.');
2288 $data = $this->getData();
2289 $pre = substr($data, 0, $offset);
2290 $post = substr($data, $offset);
2292 $this->setText(($pre . $arg . $post));
2297 * Deletes a subset of the current node text
2298 * @param int The starting point of the deletion
2299 * @param int The length of the deletion
2301 function deleteData($offset, $count) {
2302 $totalChars = $this->getLength();
2304 if (($offset < 0) ||
(($offset +
$count) > $totalChars)) {
2306 DOMIT_DOMException
::raiseException(DOMIT_INDEX_SIZE_ERR
,
2307 'Character Data index out of bounds.');
2311 $data = $this->getData();
2312 $pre = substr($data, 0, $offset);
2313 $post = substr($data, ($offset +
$count));
2315 $this->setText(($pre . $post));
2320 * Replaces a subset of the current node text with the specified text
2321 * @param int The starting point of the replacement
2322 * @param int The length of the replacement
2323 * @param string The replacement text
2325 function replaceData($offset, $count, $arg) {
2326 $totalChars = $this->getLength();
2328 if (($offset < 0) ||
(($offset +
$count) > $totalChars)) {
2330 DOMIT_DOMException
::raiseException(DOMIT_INDEX_SIZE_ERR
,
2331 'Character Data index out of bounds.');
2335 $data = $this->getData();
2336 $pre = substr($data, 0, $offset);
2337 $post = substr($data, ($offset +
$count));
2339 $this->setText(($pre . $arg . $post));
2342 } //DOMIT_CharacterData
2345 * A class representing the DOM Text Node
2347 * @package domit-xmlparser
2348 * @subpackage domit-xmlparser-main
2349 * @author John Heinstein <johnkarl@nbnet.nb.ca>
2351 class DOMIT_TextNode
extends DOMIT_CharacterData
{
2353 * DOM Text Node constructor
2354 * @param string The text of the node
2356 function DOMIT_TextNode($data) {
2357 $this->_constructor();
2358 $this->nodeType
= DOMIT_TEXT_NODE
;
2359 $this->nodeName
= '#text';
2360 $this->setText($data);
2364 * Returns the text contained in the current node
2365 * @return string The text of the current node
2367 function getText() {
2368 return $this->nodeValue
;
2372 * Sets the text contained in the current node to $data.
2373 * @param string The text data of the node
2375 function setText($data) {
2376 $this->nodeValue
= $data;
2380 * Splits a single node into multiple nodes, based on the specified offset
2381 * @param int The offset point for the split
2382 * @return Object The newly created text node
2384 function splitText($offset) {
2385 $totalChars = $this->getLength();
2387 if (($offset < 0) ||
($offset > $totalChars)) {
2389 DOMIT_DOMException
::raiseException(DOMIT_INDEX_SIZE_ERR
,
2390 'Character Data index out of bounds.');
2394 $data = $this->getData();
2395 $pre = substr($data, 0, $offset);
2396 $post = substr($data, $offset);
2398 $this->setText($pre);
2400 //create new text node
2401 $className = get_class($this);
2402 $newTextNode =& new $className($post);
2403 $newTextNode->ownerDocument
=& $this->ownerDocument
;
2405 if ($this->parentNode
->lastChild
->uid
== $this->uid
) {
2406 $this->parentNode
->appendChild($newTextNode);
2409 $this->parentNode
->insertBefore($newTextNode, $this);
2412 return $newTextNode;
2417 * Generates an array representation of the node and its children
2418 * @return Array A representation of the node and its children
2420 function toArray() {
2421 return $this->toString();
2425 * Copies a node and/or its children
2426 * @param boolean True if all child nodes are also to be cloned
2427 * @return Object A copy of the node and/or its children
2429 function &cloneNode($deep = false) {
2430 $className = get_class($this);
2431 $clone =& new $className($this->nodeValue
);
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 should be converted to entities
2440 * @return string The string representation
2442 function toString($htmlSafe = false, $subEntities=false) {
2443 require_once(DOMIT_INCLUDE_PATH
. 'xml_domit_utilities.php');
2444 global $DOMIT_defined_entities_flip;
2446 $result = $subEntities ? DOMIT_Utilities
::convertEntities($this->nodeValue
,
2447 $DOMIT_defined_entities_flip) : $this->nodeValue
;
2449 if ($htmlSafe) $result = $this->forHTML($result);
2456 * A class representing the DOM CDATA Section
2458 * @package domit-xmlparser
2459 * @subpackage domit-xmlparser-main
2460 * @author John Heinstein <johnkarl@nbnet.nb.ca>
2462 class DOMIT_CDATASection
extends DOMIT_TextNode
{
2464 * DOM CDATA Section node constructor
2465 * @param string The text of the node
2467 function DOMIT_CDATASection($data) {
2468 $this->_constructor();
2469 $this->nodeType
= DOMIT_CDATA_SECTION_NODE
;
2470 $this->nodeName
= '#cdata-section';
2471 $this->setText($data);
2472 } //DOMIT_CDATASection
2475 * Generates a string representation of the node and its children
2476 * @param boolean True if HTML readable output is desired
2477 * @param boolean True if illegal xml characters should be converted to entities
2478 * @return string The string representation
2480 function toString($htmlSafe = false, $subEntities=false) {
2481 $result = '<![CDATA[';
2482 $result .= $subEntities ?
str_replace("]]>", "]]>", $this->nodeValue
) :
2486 if ($htmlSafe) $result = $this->forHTML($result);
2490 } //DOMIT_CDATASection
2493 * A class representing the Attr node
2495 * @package domit-xmlparser
2496 * @subpackage domit-xmlparser-main
2497 * @author John Heinstein <johnkarl@nbnet.nb.ca>
2499 class DOMIT_Attr
extends DOMIT_Node
{
2500 /** @var boolean True if the attribute has been modified since parsing (NOT YET IMPLEMENTED!) */
2501 var $specified = false;
2502 /** @var Object A reference to the element to which the attribute is assigned */
2503 var $ownerElement = null;
2506 * DOM Attr node constructor
2507 * @param string The name of the attribute
2509 function DOMIT_Attr($name) {
2510 $this->_constructor();
2511 $this->nodeType
= DOMIT_ATTRIBUTE_NODE
;
2512 $this->nodeName
=$name;
2516 * Returns the name of the attribute
2517 * @return string The name of the attribute
2519 function getName() {
2520 return $this->nodeName
;
2524 * Indicates whether an attribute has been modified since parsing
2525 * @return boolean True if the node has been modified
2527 function getSpecified() {
2528 return $this->specified
;
2532 * Returns the value of the attribute
2533 * @return string The value of the attribute
2535 function getValue() {
2536 return $this->nodeValue
;
2540 * Sets the value of the attribute
2541 * @param string The value of the attribute
2543 function setValue($value) {
2544 $this->nodeValue
= $value;
2548 * Returns the text contained in the current node
2549 * @return string The text of the current node
2551 function getText() {
2552 return $this->nodeValue
;
2556 * Sets the text contained in the current node to $data.
2557 * @param string The text data of the node
2559 function setText($data) {
2560 $this->nodeValue
= $data;
2564 * Copies a node and/or its children
2565 * @param boolean True if all child nodes are also to be cloned
2566 * @return Object A copy of the node and/or its children
2568 function &cloneNode($deep = false) {
2569 $className = get_class($this);
2570 $clone =& new $className($this->nodeName
);
2571 $clone->nodeValue
= $this->nodeValue
;
2577 * Generates a string representation of the node and its children
2578 * @param boolean True if HTML readable output is desired
2579 * @param boolean True if HTML entities should be substituted
2580 * @return string The string representation
2582 function toString($htmlSafe = false, $subEntities=false) {
2583 require_once(DOMIT_INCLUDE_PATH
. 'xml_domit_utilities.php');
2584 global $DOMIT_defined_entities_flip;
2586 $result = ' ' . $this->nodeName
. '="';
2587 $result .= $subEntities ? DOMIT_Utilities
::convertEntities($this->nodeValue
,
2588 $DOMIT_defined_entities_flip) : $this->nodeValue
;
2591 if ($htmlSafe) $result = $this->forHTML($result);
2598 * A class representing the DOM Document Fragment node
2600 * @package domit-xmlparser
2601 * @subpackage domit-xmlparser-main
2602 * @author John Heinstein <johnkarl@nbnet.nb.ca>
2604 class DOMIT_DocumentFragment
extends DOMIT_ChildNodes_Interface
{
2606 * DOM Document Fragment node constructor
2608 function DOMIT_DocumentFragment() {
2609 $this->_constructor();
2610 $this->nodeType
= DOMIT_DOCUMENT_FRAGMENT_NODE
;
2611 $this->nodeName
='#document-fragment';
2612 $this->nodeValue
= null;
2613 $this->childNodes
= array();
2614 } //DOMIT_DocumentFragment
2617 * Generates an array representation of the node and its children
2618 * @return Array A representation of the node and its children
2620 function toArray() {
2621 $arReturn = array();
2622 $total = $this->childCount
;
2624 for ($i = 0; $i < $total; $i++
) {
2625 $arReturn[$i] = $this->childNodes
[$i]->toArray();
2632 * Copies a node and/or its children
2633 * @param boolean True if all child nodes are also to be cloned
2634 * @return Object A copy of the node and/or its children
2636 function &cloneNode($deep = false) {
2637 $className = get_class($this);
2638 $clone =& new $className();
2641 $total = $this->childCount
;
2643 for ($i = 0; $i < $total; $i++
) {
2644 $currentChild =& $this->childNodes
[$i];
2645 $clone->appendChild($currentChild->cloneNode($deep));
2653 * Generates a string representation of the node and its children
2654 * @param boolean True if HTML readable output is desired
2655 * @return string The string representation
2657 function toString($htmlSafe = false, $subEntities=false) {
2660 $myNodes =& $this->childNodes
;
2661 $total = count($myNodes);
2664 for ($i = 0; $i < $total; $i++
) {
2665 $child =& $myNodes[$i];
2666 $result .= $child->toString(false, $subEntities);
2670 if ($htmlSafe) $result = $this->forHTML($result);
2674 } //DOMIT_DocumentFragment
2677 * A class representing the DOM Comment node
2679 * @package domit-xmlparser
2680 * @subpackage domit-xmlparser-main
2681 * @author John Heinstein <johnkarl@nbnet.nb.ca>
2683 class DOMIT_Comment
extends DOMIT_CharacterData
{
2685 * DOM Comment node constructor
2688 function DOMIT_Comment($nodeValue) {
2689 $this->_constructor();
2690 $this->nodeType
= DOMIT_COMMENT_NODE
;
2691 $this->nodeName
= '#comment';
2692 $this->nodeValue
= $nodeValue;
2696 * Returns the text contained in the current node
2697 * @return string The text of the current node
2699 function getText() {
2700 return $this->nodeValue
;
2704 * Sets the text contained in the current node to $data.
2705 * @param string The text data of the node
2707 function setText($data) {
2708 $this->nodeValue
= $data;
2712 * Generates an array representation of the node and its children
2713 * @return Array A representation of the node and its children
2715 function toArray() {
2716 return $this->toString();
2720 * Copies a node and/or its children
2721 * @param boolean True if all child nodes are also to be cloned
2722 * @return Object A copy of the node and/or its children
2724 function &cloneNode($deep = false) {
2725 $className = get_class($this);
2726 $clone =& new $className($this->nodeValue
);
2732 * Generates a string representation of the node and its children
2733 * @param boolean True if HTML readable output is desired
2734 * @return string The string representation
2736 function toString($htmlSafe = false) {
2737 $result = '<!--' . $this->nodeValue
. '-->';
2739 if ($htmlSafe) $result = $this->forHTML($result);
2746 * A class representing the DOM Processing Instruction node
2748 * @package domit-xmlparser
2749 * @subpackage domit-xmlparser-main
2750 * @author John Heinstein <johnkarl@nbnet.nb.ca>
2752 class DOMIT_ProcessingInstruction
extends DOMIT_Node
{
2754 * DOM Processing Instruction node constructor
2757 function DOMIT_ProcessingInstruction($target, $data) {
2758 $this->_constructor();
2759 $this->nodeType
= DOMIT_PROCESSING_INSTRUCTION_NODE
;
2760 $this->nodeName
= $target;
2761 $this->nodeValue
= $data;
2762 } //DOMIT_ProcessingInstruction
2765 * Returns the processing instruction target
2766 * @return string The processing instruction target
2768 function getTarget() {
2769 return $this->nodeName
;
2773 * Returns the processing instruction data
2774 * @return string The processing instruction data
2776 function getData() {
2777 return $this->nodeValue
;
2781 * Returns the text contained in the current node
2782 * @return string The text of the current node
2784 function getText() {
2785 return ($this->nodeName
. ' ' . $this->nodeValue
);
2789 * Generates an array representation of the node and its children
2790 * @return Array A representation of the node and its children
2792 function toArray() {
2793 return $this->toString();
2797 * Copies a node and/or its children
2798 * @param boolean True if all child nodes are also to be cloned
2799 * @return Object A copy of the node and/or its children
2801 function &cloneNode($deep = false) {
2802 $className = get_class($this);
2803 $clone =& new $className($this->nodeName
, $this->nodeValue
);
2809 * Generates a string representation of the node and its children
2810 * @param boolean True if HTML readable output is desired
2811 * @return string The string representation
2813 function toString($htmlSafe = false) {
2814 $result = '<' . '?' . $this->nodeName
. ' ' . $this->nodeValue
. '?' . '>';
2816 if ($htmlSafe) $result = $this->forHTML($result);
2820 } //DOMIT_ProcessingInstruction
2823 * A class representing the DOM Document Type node
2825 * @package domit-xmlparser
2826 * @subpackage domit-xmlparser-main
2827 * @author John Heinstein <johnkarl@nbnet.nb.ca>
2829 class DOMIT_DocumentType
extends DOMIT_Node
{
2830 /** @var string The doctype name */
2832 /** @var Object True if the entity has been modified since parsing (NOT YET IMPLEMENTED!) */
2834 /** @var Object A NodeList of notation nodes (NOT YET IMPLEMENTED!) */
2836 /** @var Object A NodeList of elements (NOT YET IMPLEMENTED!) */
2838 /** @var string The full text of the doctype */
2840 /** @var string The public identifier of the external subset */
2842 /** @var string The system identifier of the external subset */
2844 /** @var string The full text of internal subset */
2845 var $internalSubset;
2848 * DOM Document Type node constructor
2851 function DOMIT_DocumentType($name, $text) {
2852 $this->_constructor();
2853 $this->nodeType
= DOMIT_DOCUMENT_TYPE_NODE
;
2854 $this->nodeName
= $name;
2855 $this->name
= $name;
2856 $this->entities
= null; //implement later
2857 $this->notations
= null; //implement later
2858 $this->elements
= null; //implement later
2859 $this->text
= $text;
2860 } //DOMIT_DocumentType
2863 * Returns the text contained in the current node
2864 * @return string The text of the current node
2866 function getText() {
2871 * Returns the name of the doctype node
2872 * @return string The name of the doctype node
2874 function getName() {
2879 * Generates an array representation of the node and its children
2880 * @return Array A representation of the node and its children
2882 function toArray() {
2883 return $this->toString();
2887 * Copies a node and/or its children
2888 * @param boolean True if all child nodes are also to be cloned
2889 * @return Object A copy of the node and/or its children
2891 function &cloneNode($deep = false) {
2892 $className = get_class($this);
2893 $clone =& new $className($this->nodeName
, $this->text
);
2899 * Generates a string representation of the node and its children
2900 * @param boolean True if HTML readable output is desired
2901 * @return string The string representation
2903 function toString($htmlSafe = false) {
2904 $result = $this->text
;
2906 if ($htmlSafe) $result = $this->forHTML($result);
2910 } //DOMIT_DocumentType
2914 * A class representing the DOM Notation node (NOT YET IMPLEMENTED!)
2916 * @package domit-xmlparser
2917 * @subpackage domit-xmlparser-main
2918 * @author John Heinstein <johnkarl@nbnet.nb.ca>
2920 class DOMIT_Notation
extends DOMIT_Node
{
2922 * DOM Notation node constructor (NOT YET IMPLEMENTED!)
2924 function DOMIT_Notation() {
2925 DOMIT_DOMException
::raiseException(DOMIT_NOT_SUPPORTED_ERR
,
2926 'Cannot instantiate DOMIT_Notation class. Notation nodes not yet supported.');
2931 * Manages the generation of a DOMIT! document from SAX events
2933 * @package domit-xmlparser
2934 * @subpackage domit-xmlparser-main
2935 * @author John Heinstein <johnkarl@nbnet.nb.ca>
2937 class DOMIT_Parser
{
2938 /** @var Object A reference to the resulting xmldoc */
2940 /** @var Object A reference to the current node in the parsing process */
2941 var $currentNode = null;
2942 /** @var Object A reference to the last child in the parsing process */
2943 var $lastChild = null;
2944 /** @var boolean True if currently parsing a CDATA Section */
2945 var $inCDATASection = false; //flag for Expat
2946 /** @var boolean True if currently parsing a Text node */
2947 var $inTextNode = false;
2948 /** @var boolean True is CDATA Section nodes are not to be converted into Text nodes */
2950 /** @var string A container for holding the currently parsed text data */
2951 var $parseContainer = '';
2952 /** @var string The current docutype text */
2953 var $parseItem = '';
2954 /** @var array An array of namespacesURIs mapped to prefixes */
2955 var $namespaceURIMap = array();
2958 * Parses xml text using Expat
2959 * @param Object A reference to the DOM document that the xml is to be parsed into
2960 * @param string The text to be parsed
2961 * @param boolean True if CDATA Section nodes are not to be converted into Text nodes
2962 * @return boolean True if the parsing is successful
2964 function parse (&$myXMLDoc, $xmlText, $preserveCDATA = true) {
2965 $this->xmlDoc
=& $myXMLDoc;
2966 $this->lastChild
=& $this->xmlDoc
;
2968 $this->preserveCDATA
= $preserveCDATA;
2970 //create instance of expat parser (should be included in php distro)
2971 if (version_compare(phpversion(), '5.0', '<=')) {
2972 if ($this->xmlDoc
->isNamespaceAware
) {
2973 $parser = xml_parser_create_ns('');
2976 $parser = xml_parser_create('');
2980 if ($this->xmlDoc
->isNamespaceAware
) {
2981 $parser = xml_parser_create_ns();
2984 $parser = xml_parser_create();
2988 //set handlers for SAX events
2989 xml_set_object($parser, $this);
2990 xml_set_character_data_handler($parser, 'dataElement');
2991 xml_set_default_handler($parser, 'defaultDataElement');
2992 xml_set_notation_decl_handler($parser, 'notationElement');
2993 xml_set_processing_instruction_handler($parser, 'processingInstructionElement');
2994 xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING
, 0);
2995 xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE
, 1);
2997 if ($this->xmlDoc
->isNamespaceAware
) {
2998 xml_set_start_namespace_decl_handler($parser, 'startNamespaceDeclaration');
2999 xml_set_end_namespace_decl_handler($parser, 'endNamespaceDeclaration');
3000 xml_set_element_handler($parser, 'startElementNS', 'endElement');
3001 $this->namespaceURIMap
[DOMIT_XML_NAMESPACE
] = 'xml';
3004 xml_set_element_handler($parser, 'startElement', 'endElement');
3007 //parse out whitespace - (XML_OPTION_SKIP_WHITE = 1 does not
3008 //seem to work consistently across versions of PHP and Expat
3009 $xmlText = eregi_replace('>' . "[[:space:]]+" . '<' , '><', $xmlText);
3011 $success = xml_parse($parser, $xmlText);
3013 $this->xmlDoc
->errorCode
= xml_get_error_code($parser);
3014 $this->xmlDoc
->errorString
= xml_error_string($this->xmlDoc
->errorCode
);
3016 xml_parser_free($parser);
3022 * Parses xml text using SAXY
3023 * @param Object A reference to the DOM document that the xml is to be parsed into
3024 * @param string The text to be parsed
3025 * @param boolean True if CDATA Section nodes are not to be converted into Text nodes
3026 * @return boolean True if the parsing is successful
3028 function parseSAXY(&$myXMLDoc, $xmlText, $preserveCDATA = true, $definedEntities) {
3029 require_once(DOMIT_INCLUDE_PATH
. 'xml_saxy_parser.php');
3031 $this->xmlDoc
=& $myXMLDoc;
3032 $this->lastChild
=& $this->xmlDoc
;
3034 //create instance of SAXY parser
3035 $parser =& new SAXY_Parser();
3036 $parser->appendEntityTranslationTable($definedEntities);
3038 if ($this->xmlDoc
->isNamespaceAware
) {
3039 $parser->setNamespaceAwareness(true);
3040 $parser->xml_set_start_namespace_decl_handler(array(&$this, 'startNamespaceDeclaration'));
3041 $parser->xml_set_end_namespace_decl_handler(array(&$this, 'endNamespaceDeclaration'));
3042 $parser->xml_set_element_handler(array(&$this, 'startElementNS'), array(&$this, 'endElement'));
3043 $this->namespaceURIMap
[DOMIT_XML_NAMESPACE
] = 'xml';
3046 $parser->xml_set_element_handler(array(&$this, 'startElement'), array(&$this, 'endElement'));
3049 $parser->xml_set_character_data_handler(array(&$this, 'dataElement'));
3050 $parser->xml_set_doctype_handler(array(&$this, 'doctypeElement'));
3051 $parser->xml_set_comment_handler(array(&$this, 'commentElement'));
3052 $parser->xml_set_processing_instruction_handler(array(&$this, 'processingInstructionElement'));
3054 if ($preserveCDATA) {
3055 $parser->xml_set_cdata_section_handler(array(&$this, 'cdataElement'));
3058 $success = $parser->parse($xmlText);
3060 $this->xmlDoc
->errorCode
= $parser->xml_get_error_code();
3061 $this->xmlDoc
->errorString
= $parser->xml_error_string($this->xmlDoc
->errorCode
);
3067 * Generates and appends a new text node from the parseContainer text
3069 function dumpTextNode() {
3070 $currentNode =& $this->xmlDoc
->createTextNode($this->parseContainer
);
3071 $this->lastChild
->appendChild($currentNode);
3072 $this->inTextNode
= false;
3073 $this->parseContainer
= '';
3077 * Catches a start element event and processes the data
3078 * @param Object A reference to the current SAX parser
3079 * @param string The tag name of the current element
3080 * @param Array An array of the element attributes
3082 function startElement(&$parser, $name, $attrs) {
3083 if ($this->inTextNode
) {
3084 $this->dumpTextNode();
3087 $currentNode =& $this->xmlDoc
->createElement($name);
3088 $this->lastChild
->appendChild($currentNode);
3092 while (list($key, $value) = each ($attrs)) {
3093 $currentNode->setAttribute($key, $value);
3096 $this->lastChild
=& $currentNode;
3100 * Catches a start element event and processes the data
3101 * @param Object A reference to the current SAX parser
3102 * @param string The tag name of the current element
3103 * @param Array An array of the element attributes
3105 function startElementNS(&$parser, $name, $attrs) {
3106 $colonIndex = strrpos($name, ":");
3108 if ($colonIndex !== false) {
3109 //force to lower case because Expat for some reason forces to upper case
3110 $namespaceURI = strtolower(substr($name, 0, $colonIndex));
3111 $prefix = $this->namespaceURIMap
[$namespaceURI];
3113 if ($prefix != '') {
3114 $qualifiedName = $prefix . ":" . substr($name, ($colonIndex +
1));
3117 $qualifiedName = substr($name, ($colonIndex +
1));
3122 $qualifiedName = $name;
3125 $currentNode =& $this->xmlDoc
->createElementNS($namespaceURI, $qualifiedName);
3126 $this->lastChild
->appendChild($currentNode);
3130 while (list($key, $value) = each ($attrs)) {
3131 $colonIndex = strrpos($key, ":");
3133 if ($colonIndex !== false) {
3134 //force to lower case because Expat for some reason forces to upper case
3135 $namespaceURI = strtolower(substr($key, 0, $colonIndex));
3137 if ($namespaceURI == 'xmlns') {
3138 //$qualifiedName = substr($key, ($colonIndex + 1));
3139 $qualifiedName = $key;
3142 $qualifiedName = $this->namespaceURIMap
[$namespaceURI] .
3143 ":" . substr($key, ($colonIndex +
1));;
3148 $qualifiedName = $key;
3151 $currentNode->setAttributeNS($namespaceURI, $qualifiedName, $value);
3154 $this->lastChild
=& $currentNode;
3159 * Catches an end element event and processes the data
3160 * @param Object A reference to the current SAX parser
3161 * @param string The tag name of the current element
3163 function endElement(&$parser, $name) {
3164 if ($this->inTextNode
) {
3165 $this->dumpTextNode();
3168 $this->lastChild
=& $this->lastChild
->parentNode
;
3172 * Catches a data event and processes the text
3173 * @param Object A reference to the current SAX parser
3174 * @param string The current text data
3176 function dataElement(&$parser, $data) {
3177 if (!$this->inCDATASection
) {
3178 $this->inTextNode
= true;
3181 $this->parseContainer
.= $data;
3185 * Catches a CDATA Section event and processes the text
3186 * @param Object A reference to the current SAX parser
3187 * @param string The current text data
3189 function cdataElement(&$parser, $data) {
3190 $currentNode =& $this->xmlDoc
->createCDATASection($data);
3192 $this->lastChild
->appendChild($currentNode);
3196 * Catches a default data event and processes the data
3197 * @param Object A reference to the current SAX parser
3198 * @param string The current data
3200 function defaultDataElement(&$parser, $data) {
3201 if ((strlen($data) > 2) && ($this->parseItem
== '')){
3202 $pre = strtoupper(substr($data, 0, 3));
3205 case '<?X': //xml declaration
3206 $this->processingInstructionElement($parser, 'xml', substr($data, 6, (strlen($data) - 6 - 2)));
3208 case '<!E': //dtd entity
3209 $this->xmlDoc
->doctype
.= "\n " . $data;
3211 case '<![': //cdata section coming
3212 if ($this->preserveCDATA
) {
3213 $this->inCDATASection
= true;
3216 case '<!-': //comment
3217 $currentNode =& $this->commentElement($this, substr($data, 4, (strlen($data) - 7)));
3219 case '<!D': //doctype
3220 $this->parseItem
= 'doctype';
3221 $this->parseContainer
= $data;
3223 case ']]>': //cdata end tag
3224 $this->inCDATASection
= false;
3225 $currentNode =& $this->xmlDoc
->createCDataSection($this->parseContainer
);
3226 $this->lastChild
->appendChild($currentNode);
3227 $this->parseContainer
= '';
3232 switch ($this->parseItem
) {
3234 $this->parseContainer
.= $data;
3237 $this->doctypeElement($parser, $this->parseContainer
);
3238 $this->parseContainer
= '';
3239 $this->parseItem
= '';
3241 else if ($data == '[') {
3242 $this->parseItem
= 'doctype_inline';
3246 case 'doctype_inline':
3247 $this->parseContainer
.= $data;
3250 $this->parseItem
= 'doctype';
3252 else if ($data{(strlen($data) - 1)} == '>') {
3253 $this->parseContainer
.= "\n ";
3258 } //defaultDataElement
3261 * Catches a doctype event and processes the data
3262 * @param Object A reference to the current SAX parser
3263 * @param string The current data
3265 function doctypeElement(&$parser, $data) {
3266 $start = strpos($data, '<!DOCTYPE');
3267 $name = trim(substr($data, $start));
3268 $end = strpos($name, ' ');
3269 $name = substr($name, 0, $end);
3271 $currentNode =& new DOMIT_DocumentType($name, $data);
3272 $currentNode->ownerDocument
=& $this->xmlDoc
;
3274 $this->lastChild
->appendChild($currentNode);
3275 $this->xmlDoc
->doctype
=& $currentNode;
3279 * Catches a notation node event and processes the data
3280 * @param Object A reference to the current SAX parser
3281 * @param string The current notation data
3283 function notationElement(&$parser, $data) {
3284 //add to doctype string
3285 if (($this->parseItem
== 'doctype_inline') ||
($this->parseItem
== 'doctype')) {
3286 $this->parseContainer
.= $data;
3291 * Catches a comment node event and processes the data
3292 * @param Object A reference to the current SAX parser
3293 * @param string The comment data
3295 function commentElement(&$parser, $data) {
3296 if ($this->inTextNode
) {
3297 $this->dumpTextNode();
3300 $currentNode =& $this->xmlDoc
->createComment($data);
3301 $this->lastChild
->appendChild($currentNode);
3305 * Catches a processing instruction node event and processes the data
3306 * @param Object A reference to the current SAX parser
3307 * @param string The target of the processing instruction data
3308 * @param string The processing instruction data
3310 function processingInstructionElement(&$parser, $target, $data) {
3311 if ($this->inTextNode
) {
3312 $this->dumpTextNode();
3315 $currentNode =& $this->xmlDoc
->createProcessingInstruction($target, $data);
3316 $this->lastChild
->appendChild($currentNode);
3318 if (strtolower($target) == 'xml') {
3319 $this->xmlDoc
->xmldeclaration
=& $currentNode;
3321 } //processingInstructionElement
3324 * Catches a start namespace declaration event and processes the data
3325 * @param Object A reference to the current SAX parser
3326 * @param string The namespace prefix
3327 * @param string The namespace uri
3329 function startNamespaceDeclaration(&$parser, $prefix, $uri) {
3330 //make uri lower case because Expat forces it to upper case for some reason
3331 $this->namespaceURIMap
[strtolower($uri)] = $prefix;
3332 } //startNamespaceDeclaration
3335 * Catches an end namespace declaration event
3336 * @param Object A reference to the current SAX parser
3337 * @param string The namespace prefix
3339 function endNamespaceDeclaration(&$parser, $prefix) {
3340 //do nothing; could remove from map, but would hardly be optimal
3341 } //endNamespaceDeclaration