PHP Classes

File: xml_domit_parser.php

Recommend this page to a friend!
  Classes of John Heinstein  >  DOMIT XML parser  >  xml_domit_parser.php  >  Download  
File: xml_domit_parser.php
Role: Class source
Content type: text/plain
Description: The main xml parser classes
Class: DOMIT XML parser
A Document Object Model (DOM) compliant xml parser
Author: By
Last change:
Date: 17 years ago
Size: 110,416 bytes
 

Contents

Class file image Download
<?php /** * DOMIT! is a non-validating, but lightweight and fast DOM parser for PHP * @package domit-xmlparser * @subpackage domit-xmlparser-main * @version 1.01 * @copyright (C) 2004 John Heinstein. All rights reserved * @license http://www.gnu.org/copyleft/lesser.html LGPL License * @author John Heinstein <johnkarl@nbnet.nb.ca> * @link http://www.engageinteractive.com/domit/ DOMIT! Home Page * DOMIT! is Free Software **/ if (!defined('DOMIT_INCLUDE_PATH')) { define('DOMIT_INCLUDE_PATH', (dirname(__FILE__) . "/")); } /** current version of DOMIT! */ define ('DOMIT_VERSION', '1.01'); /** XML namespace URI */ define ('DOMIT_XML_NAMESPACE', 'http://www.w3.org/xml/1998/namespace'); /** XMLNS namespace URI */ define ('DOMIT_XMLNS_NAMESPACE', 'http://www.w3.org/2000/xmlns/'); /** * @global array Flipped version of $definedEntities array, to allow two-way conversion of entities * * Made global so that Attr nodes, which have no ownerDocument property, can access the array */ $GLOBALS['DOMIT_defined_entities_flip'] = array(); require_once(DOMIT_INCLUDE_PATH . 'xml_domit_shared.php'); /** * The base class of all DOMIT node types * * @package domit-xmlparser * @subpackage domit-xmlparser-main * @author John Heinstein <johnkarl@nbnet.nb.ca> */ class DOMIT_Node { /** @var string The name of the node, varies according to node type */ var $nodeName = null; /** @var string The value of the node, varies according to node type */ var $nodeValue = null; /** @var int The type of node, e.g. CDataSection */ var $nodeType = null; /** @var Object A reference to the parent of the current node */ var $parentNode = null; /** @var Array An array of child node references */ var $childNodes = null; /** @var Object A reference to the first node in the childNodes list */ var $firstChild = null; /** @var Object A reference to the last node in the childNodes list */ var $lastChild = null; /** @var Object A reference to the node prior to the current node in its parents childNodes list */ var $previousSibling = null; /** @var Object A reference to the node after the current node in its parents childNodes list */ var $nextSibling = null; /** @var Object A NodeList of attribute nodes */ var $attributes = null; /** @var Object A reference to the Document node */ var $ownerDocument = null; /** @var String A URI that identifies the XML namespace to which the node belongs */ var $namespaceURI = null; /** @var String The namespace prefix for the node */ var $prefix = null; /** @var String The local name of the node */ var $localName = null; /** @var string The unique node id */ var $uid; /** @var int The number of children of the current node */ var $childCount = 0; /** * Raises error if abstract class is directly instantiated */ function DOMIT_Node() { DOMIT_DOMException::raiseException(DOMIT_ABSTRACT_CLASS_INSTANTIATION_ERR, 'Cannot instantiate abstract class DOMIT_Node'); } //DOMIT_Node /** * DOMIT_Node constructor, assigns a uid */ function _constructor() { global $uidFactory; $this->uid = $uidFactory->generateUID(); } //_constructor /** * Appends a node to the childNodes list of the current node * @abstract * @param Object The node to be appended * @return Object The appended node */ function &appendChild(&$child) { DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR, ('Method appendChild cannot be called by class ' . get_class($this))); } //appendChild /** * Inserts a node to the childNodes list of the current node * @abstract * @param Object The node to be inserted * @param Object The node before which the insertion is to occur * @return Object The inserted node */ function &insertBefore(&$newChild, &$refChild) { DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR, ('Method insertBefore cannot be called by class ' . get_class($this))); } //insertBefore /** * Replaces a node with another * @abstract * @param Object The new node * @param Object The old node * @return Object The new node */ function &replaceChild(&$newChild, &$oldChild) { DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR, ('Method replaceChild cannot be called by class ' . get_class($this))); } //replaceChild /** * Removes a node from the childNodes list of the current node * @abstract * @param Object The node to be removed * @return Object The removed node */ function &removeChild(&$oldChild) { DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR, ('Method removeChild cannot be called by class ' . get_class($this))); } //removeChild /** * Returns the index of the specified node in a childNodes list * @param Array The childNodes array to be searched * @param Object The node targeted by the search * @return int The index of the target node, or -1 if not found */ function getChildNodeIndex(&$arr, &$child) { $index = -1; $total = count($arr); for ($i = 0; $i < $total; $i++) { if ($child->uid == $arr[$i]->uid) { $index = $i; break; } } return $index; } //getChildNodeIndex /** * Determines whether a node has any children * @return boolean True if any child nodes are present */ function hasChildNodes() { return ($this->childCount > 0); } //hasChildNodes /** * Determines whether a node has any attributes * @return boolean True if the node has attributes */ function hasAttributes() { //overridden in DOMIT_Element return false; } //hasChildNodes /** * Collapses adjacent text nodes in entire node subtree */ function normalize() { if (($this->nodeType == DOMIT_DOCUMENT_NODE) && ($this->documentElement != null)) { $this->documentElement->normalize(); } } //normalize /** * Copies a node and/or its children * @abstract * @param boolean True if all child nodes are also to be cloned * @return Object A copy of the node and/or its children */ function &cloneNode($deep = false) { DOMIT_DOMException::raiseException(DOMIT_ABSTRACT_METHOD_INVOCATION_ERR, 'Cannot invoke abstract method DOMIT_Node->cloneNode($deep). Must provide an overridden method in your subclass.'); } //cloneNode /** * Adds elements with the specified tag name to a NodeList collection * @param Object The NodeList collection * @param string The tag name of matching elements */ function getNamedElements(&$nodeList, $tagName) { //Implemented in DOMIT_Element. //Needs to be here though! This is called against all nodes in the document. } //getNamedElements /** * Sets the ownerDocument property of a node to the containing DOMIT_Document * @param Object A reference to the document element of the DOMIT_Document */ function setOwnerDocument(&$rootNode) { if ($rootNode->ownerDocument == null) { unset($this->ownerDocument); $this->ownerDocument = null; } else { $this->ownerDocument =& $rootNode->ownerDocument; } $total = $this->childCount; for ($i = 0; $i < $total; $i++) { $this->childNodes[$i]->setOwnerDocument($rootNode); } } //setOwnerDocument /** * Tests whether a value is null, and if so, returns a default value * @param mixed The value to be tested * @param mixed The default value * @return mixed The specified value, or the default value if null */ function &nvl(&$value,$default) { if (is_null($value)) return $default; return $value; } //nvl /** * Retrieves an element or DOMIT_NodeList of elements corresponding to an Xpath-like expression. * @abstract * @param string The query pattern * @param int If a single node is to be returned (rather than the entire NodeList) the index of that node * @return mixed A NodeList or single node that matches the pattern */ function &getElementsByPath($pattern, $nodeIndex = 0) { DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR, ('Method getElementsByPath cannot be called by class ' . get_class($this))); } //getElementsByPath /** * Retrieves an element or DOMIT_NodeList of elements corresponding to an Xpath-like attribute expression (NOT YET IMPLEMENTED!) * @abstract * @param string The query pattern * @param int If a single node is to be returned (rather than the entire NodeList) the index of that node * @return mixed A NodeList or single node that matches the pattern */ function &getElementsByAttributePath($pattern, $nodeIndex = 0) { DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR, ('Method getElementsByAttributePath cannot be called by class ' . get_class($this))); } //getElementsByAttributePath /** * Adds all child nodes of the specified nodeType to the NodeList * @abstract * @param Object The NodeList collection * @param string The nodeType of matching nodes */ function getTypedNodes(&$nodeList, $type) { DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR, ('Method getTypedNodes cannot be called by class ' . get_class($this))); } //getTypedNodes /** * Adds all child nodes of the specified nodeValue to the NodeList * @abstract * @param Object The NodeList collection * @param string The nodeValue of matching nodes */ function getValuedNodes(&$nodeList, $value) { DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR, ('Method getValuedNodes cannot be called by class ' . get_class($this))); } //getValuedNodes /** * Returns the concatented text of the current node and its children * @return string The concatented text of the current node and its children */ function getText() { return $this->nodeValue; } //getText /** * Indicates whether the specified feature is supported by the DOM implementation and this node * @param string The feature * @param string The version of the DOM implementation * @return boolean True if the specified feature is supported */ function isSupported($feature, $version = null) { //don't worry about parsing based on version at this point in time; //the only feature that is supported is 'XML'... if (($version == '1.0') || ($version == '2.0') || ($version == null)) { if (strtoupper($feature) == 'XML') { return true; } } return false; } //isSupported /** * Formats a string for presentation as HTML * @param string The string to be formatted * @param boolean True if the string is to be sent directly to output * @return string The HTML formatted string */ function forHTML($str, $doPrint = false) { require_once(DOMIT_INCLUDE_PATH . 'xml_domit_utilities.php'); return DOMIT_Utilities::forHTML($str, $doPrint); } //forHTML /** * Generates an array representation of the node and its children * @abstract * @return Array A representation of the node and its children */ function toArray() { DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR, ('Method toArray cannot be called by class ' . get_class($this))); } //toArray /** * A node event that can be set to fire upon document loading, used for node initialization * @abstract */ function onLoad() { //you can override this method if you subclass any of the //DOMIT_Nodes. It's a way of performing //initialization of your subclass as soon as the document //has been loaded (as opposed to as soon as the current node //has been instantiated). } //onLoad /** * Clears previousSibling, nextSibling, and parentNode references from a node that has been removed */ function clearReferences() { if ($this->previousSibling != null) { unset($this->previousSibling); $this->previousSibling = null; } if ($this->nextSibling != null) { unset($this->nextSibling); $this->nextSibling = null; } if ($this->parentNode != null) { unset($this->parentNode); $this->parentNode = null; } } //clearReferences /** * Removes the node from the document */ function delete () { if ($this->parentNode != null) { $this->parentNode->removeChild($node); } } //delete /** * Generates a normalized (formatted for readability) representation of the node and its children * @param boolean True if HTML readable output is desired * @param boolean True if illegal xml characters in text nodes and attributes should be converted to entities * @return string The formatted string representation */ function toNormalizedString($htmlSafe = false, $subEntities = false) { //require this file for generating a normalized (readable) xml string representation require_once(DOMIT_INCLUDE_PATH . 'xml_domit_utilities.php'); global $DOMIT_defined_entities_flip; $result = DOMIT_Utilities::toNormalizedString($this, $subEntities, $DOMIT_defined_entities_flip); if ($htmlSafe) $result = $this->forHTML($result); return $result; } //toNormalizedString } //DOMIT_Node /** * A parent class for nodes which possess child nodes * * @package domit-xmlparser * @subpackage domit-xmlparser-main * @author John Heinstein <johnkarl@nbnet.nb.ca> */ class DOMIT_ChildNodes_Interface extends DOMIT_Node { /** * Raises error if abstract class is directly instantiated */ function DOMIT_ChildNodes_Interface() { DOMIT_DOMException::raiseException(DOMIT_ABSTRACT_CLASS_INSTANTIATION_ERR, 'Cannot instantiate abstract class DOMIT_ChildNodes_Interface'); } //DOMIT_ChildNodes_Interface /** * Appends a node to the childNodes list of the current node * @param Object The node to be appended * @return Object The appended node */ function &appendChild(&$child) { if ($child->nodeType == DOMIT_ATTRIBUTE_NODE) { DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR, ('Cannot add a node of type ' . get_class($child) . ' using appendChild')); } else if ($child->nodeType == DOMIT_DOCUMENT_FRAGMENT_NODE) { $total = $child->childCount; for ($i = 0; $i < $total; $i++) { $currChild =& $child->childNodes[$i]; $this->appendChild($currChild); } } else { if (!($this->hasChildNodes())) { $this->childNodes[0] =& $child; $this->firstChild =& $child; } else { //remove $child if it already exists $index = $this->getChildNodeIndex($this->childNodes, $child); if ($index != -1) { $this->removeChild($child); } //append child $numNodes = $this->childCount; $prevSibling =& $this->childNodes[($numNodes - 1)]; $this->childNodes[$numNodes] =& $child; //set next and previous relationships $child->previousSibling =& $prevSibling; $prevSibling->nextSibling =& $child; } $this->lastChild =& $child; $child->parentNode =& $this; unset($child->nextSibling); $child->nextSibling = null; $child->setOwnerDocument($this); $this->childCount++; } return $child; } //appendChild /** * Inserts a node to the childNodes list of the current node * @param Object The node to be inserted * @param Object The node before which the insertion is to occur * @return Object The inserted node */ function &insertBefore(&$newChild, &$refChild) { if ($newChild->nodeType == DOMIT_ATTRIBUTE_NODE) { DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR, ('Cannot add a node of type ' . get_class($newChild) . ' using insertBefore')); } if (($refChild->nodeType == DOMIT_DOCUMENT_NODE) || //($refChild->parentNode->nodeType == DOMIT_DOCUMENT_NODE) || ($refChild->parentNode == null)) { DOMIT_DOMException::raiseException(DOMIT_NOT_FOUND_ERR, 'Reference child not present in the child nodes list.'); } //if reference child is also the node to be inserted //leave the document as is and don't raise an exception if ($refChild->uid == $newChild->uid) { return $newChild; } //if $newChild is a DocumentFragment, //loop through and insert each node separately if ($newChild->nodeType == DOMIT_DOCUMENT_FRAGMENT_NODE) { $total = $newChild->childCount; for ($i = 0; $i < $total; $i++) { $currChild =& $newChild->childNodes[$i]; $this->insertBefore($currChild, $refChild); } return $newChild; } //remove $newChild if it already exists $index = $this->getChildNodeIndex($this->childNodes, $newChild); if ($index != -1) { $this->removeChild($newChild); } //find index of $refChild in childNodes $index = $this->getChildNodeIndex($this->childNodes, $refChild); if ($index != -1) { //reset sibling chain if ($refChild->previousSibling != null) { $refChild->previousSibling->nextSibling =& $newChild; $newChild->previousSibling =& $refChild->previousSibling; } else { $this->firstChild =& $newChild; if ($newChild->previousSibling != null) { unset($newChild->previousSibling); $newChild->previousSibling = null; } } $newChild->parentNode =& $refChild->parentNode; $newChild->nextSibling =& $refChild; $refChild->previousSibling =& $newChild; //add node to childNodes $i = $this->childCount; while ($i >= 0) { if ($i > $index) { $this->childNodes[$i] =& $this->childNodes[($i - 1)]; } else if ($i == $index) { $this->childNodes[$i] =& $newChild; } $i--; } $this->childCount++; } else { $this->appendChild($newChild); } $newChild->setOwnerDocument($this); return $newChild; } //insertBefore /** * Replaces a node with another * @param Object The new node * @param Object The old node * @return Object The new node */ function &replaceChild(&$newChild, &$oldChild) { if ($newChild->nodeType == DOMIT_ATTRIBUTE_NODE) { DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR, ('Cannot add a node of type ' . get_class($newChild) . ' using replaceChild')); } else if ($newChild->nodeType == DOMIT_DOCUMENT_FRAGMENT_NODE) { //if $newChild is a DocumentFragment //replace the first node then loop through and insert each node separately $total = $newChild->childCount; if ($total > 0) { $newRef =& $newChild->lastChild; $this->replaceChild($newRef, $oldChild); for ($i = 0; $i < ($total - 1); $i++) { $currChild =& $newChild->childNodes[$i]; $this->insertBefore($currChild, $newRef); } } return $newChild; } else { if ($this->hasChildNodes()) { //remove $newChild if it already exists $index = $this->getChildNodeIndex($this->childNodes, $newChild); if ($index != -1) { $this->removeChild($newChild); } //find index of $oldChild in childNodes $index = $this->getChildNodeIndex($this->childNodes, $oldChild); if ($index != -1) { $newChild->ownerDocument =& $oldChild->ownerDocument; $newChild->parentNode =& $oldChild->parentNode; //reset sibling chain if ($oldChild->previousSibling == null) { unset($newChild->previousSibling); $newChild->previousSibling = null; } else { $oldChild->previousSibling->nextSibling =& $newChild; $newChild->previousSibling =& $oldChild->previousSibling; } if ($oldChild->nextSibling == null) { unset($newChild->nextSibling); $newChild->nextSibling = null; } else { $oldChild->nextSibling->previousSibling =& $newChild; $newChild->nextSibling =& $oldChild->nextSibling; } $this->childNodes[$index] =& $newChild; if ($index == 0) $this->firstChild =& $newChild; if ($index == ($this->childCount - 1)) $this->lastChild =& $newChild; $newChild->setOwnerDocument($this); return $newChild; } } DOMIT_DOMException::raiseException(DOMIT_NOT_FOUND_ERR, ('Reference node for replaceChild not found.')); } } //replaceChild /** * Removes a node from the childNodes list of the current node * @param Object The node to be removed * @return Object The removed node */ function &removeChild(&$oldChild) { if ($this->hasChildNodes()) { //find index of $oldChild in childNodes $index = $this->getChildNodeIndex($this->childNodes, $oldChild); if ($index != -1) { //reset sibling chain if (($oldChild->previousSibling != null) && ($oldChild->nextSibling != null)) { $oldChild->previousSibling->nextSibling =& $oldChild->nextSibling; $oldChild->nextSibling->previousSibling =& $oldChild->previousSibling; } else if (($oldChild->previousSibling != null) && ($oldChild->nextSibling == null)) { $this->lastChild =& $oldChild->previousSibling; unset($oldChild->previousSibling->nextSibling); $oldChild->previousSibling->nextSibling = null; } else if (($oldChild->previousSibling == null) && ($oldChild->nextSibling != null)) { unset($oldChild->nextSibling->previousSibling); $oldChild->nextSibling->previousSibling = null; $this->firstChild =& $oldChild->nextSibling; } else if (($oldChild->previousSibling == null) && ($oldChild->nextSibling == null)) { unset($this->firstChild); $this->firstChild = null; unset($this->lastChild); $this->lastChild = null; } $total = $this->childCount; //remove node from childNodes for ($i = 0; $i < $total; $i++) { if ($i == ($total - 1)) { array_splice($this->childNodes, $i, 1); } else if ($i >= $index) { $this->childNodes[$i] =& $this->childNodes[($i + 1)]; } } $this->childCount--; $oldChild->clearReferences(); return $oldChild; } } DOMIT_DOMException::raiseException(DOMIT_NOT_FOUND_ERR, ('Target node for removeChild not found.')); } //removeChild /** * Searches the element tree for an element with the specified attribute name and value. * @param string The value of the attribute * @param string The name of the attribute * @param boolean True if the first found node is to be returned as a node instead of a nodelist * @param boolean True if uid is to be considered an attribute * @return object A NodeList of found elements, or null */ function &getElementsByAttribute($attrName = 'id', $attrValue = '', $returnFirstFoundNode = false, $treatUIDAsAttribute = false) { require_once(DOMIT_INCLUDE_PATH . 'xml_domit_nodemaps.php'); $nodelist = new DOMIT_NodeList(); switch ($this->nodeType) { case DOMIT_ELEMENT_NODE: $this->_getElementsByAttribute($nodelist, $attrName, $attrValue, $returnFirstFoundNode, $treatUIDAsAttribute); break; case DOMIT_DOCUMENT_NODE: if ($this->documentElement != null) { $this->documentElement->_getElementsByAttribute($nodelist, $attrName, $attrValue, $returnFirstFoundNode, $treatUIDAsAttribute); } break; } if ($returnFirstFoundNode) { if ($nodelist->getLength() > 0) { return $nodelist->item(0); } else { $null = null; return $null; } } else { return $nodelist; } } //getElementsByAttribute /** * Searches the element tree for an element with the specified attribute name and value. * @param object The node list of found elements * @param string The value of the attribute * @param string The name of the attribute * @param boolean True if the first found node is to be returned as a node instead of a nodelist * @param boolean True if uid is to be considered an attribute * @param boolean True the node has been found */ function _getElementsByAttribute(&$nodelist, $attrName, $attrValue, $returnFirstFoundNode, $treatUIDAsAttribute, $foundNode = false) { if (!($foundNode && $returnFirstFoundNode)) { if (($this->getAttribute($attrName) == $attrValue) || ($treatUIDAsAttribute && ($attrName == 'uid') && ($this->uid == $attrValue))) { $nodelist->appendNode($this); $foundNode = true; if ($returnFirstFoundNode) return; } $total = $this->childCount; for ($i = 0; $i < $total; $i++) { $currNode =& $this->childNodes[$i]; if ($currNode->nodeType == DOMIT_ELEMENT_NODE) { $currNode->_getElementsByAttribute($nodelist, $attrName, $attrValue, $returnFirstFoundNode, $treatUIDAsAttribute, $foundNode); } } } } //_getElementsByAttribute /** * Performs an XPath query * @param string The query pattern * @return Object A NodeList containing the found nodes */ function &selectNodes($pattern, $nodeIndex = 0) { require_once(DOMIT_INCLUDE_PATH . 'xml_domit_xpath.php'); $xpParser = new DOMIT_XPath(); return $xpParser->parsePattern($this, $pattern, $nodeIndex); } //selectNodes /** * Converts the childNodes array into a NodeList object * @return Object A NodeList containing elements of the childNodes array */ function &childNodesAsNodeList() { require_once('xml_domit_nodemaps.php'); $myNodeList = new DOMIT_NodeList(); $total = $this->childCount; for ($i = 0; $i < $total; $i++) { $myNodeList->appendNode($this->childNodes[$i]); } return $myNodeList; } //childNodesAsNodeList } //DOMIT_ChildNodes_Interface /** * A class representing the DOM Document * * @package domit-xmlparser * @subpackage domit-xmlparser-main * @author John Heinstein <johnkarl@nbnet.nb.ca> */ class DOMIT_Document extends DOMIT_ChildNodes_Interface { /** @var Object The xml declaration processing instruction */ var $xmlDeclaration; /** @var Object A reference to a DOMIT_DocType object */ var $doctype; /** @var Object A reference to the root node of the DOM document */ var $documentElement; /** @var string The parser used to process the DOM document, either "EXPAT" or "SAXY" */ var $parser; /** @var Object A reference to the DOMIT_DOMImplementation object */ var $implementation; /** @var boolean True if the DOM document has been modifed since being parsed (NOT YET IMPLEMENTED!) */ var $isModified; /** @var boolean True if whitespace is to be preserved during parsing */ var $preserveWhitespace = false; /** @var Array User defined translation table for XML entities; passed to SAXY */ var $definedEntities = array(); /** @var boolean If true, loadXML or parseXML will attempt to detect and repair invalid xml */ var $doResolveErrors = false; /** @var boolean If true, elements tags will be rendered to string as <element></element> rather than <element/> */ var $doExpandEmptyElementTags = false; /** @var array A list of exceptions to the empty element expansion rule */ var $expandEmptyElementExceptions = array(); /** @var boolean If true, namespaces will be processed */ var $isNamespaceAware = false; /** @var int The error code returned by the SAX parser */ var $errorCode = 0; /** @var string The error string returned by the SAX parser */ var $errorString = ''; /** @var object A reference to a http connection or proxy server, if one is required */ var $httpConnection = null; /** @var boolean True if php_http_client_generic is to be used instead of PHP get_file_contents to retrieve xml data */ var $doUseHTTPClient = false; /** @var array An array of namespacesURIs mapped to prefixes */ var $namespaceURIMap = array(); /** * DOM Document constructor */ function DOMIT_Document() { $this->_constructor(); $this->xmlDeclaration = null; $this->doctype = null; $this->documentElement = null; $this->nodeType = DOMIT_DOCUMENT_NODE; $this->nodeName = '#document'; $this->ownerDocument =& $this; $this->parser = ''; $this->implementation = new DOMIT_DOMImplementation(); } //DOMIT_Document /** * Specifies whether DOMIT! will try to fix invalid XML before parsing begins * @param boolean True if errors are to be resolved */ function resolveErrors($truthVal) { $this->doResolveErrors = $truthVal; } //resolveErrors /** * Specifies whether DOMIT! processes namespace information * @param boolean True if namespaces are to be processed */ function setNamespaceAwareness($truthVal) { $this->isNamespaceAware = $truthVal; } //setNamespaceAwareness /** * Specifies whether DOMIT! preserves whitespace when parsing * @param boolean True if whitespace is to be preserved */ function preserveWhitespace($truthVal) { $this->preserveWhitespace = $truthVal; } //preserveWhitespace /** * Specifies the parameters of the http conection used to obtain the xml data * @param string The ip address or domain name of the connection * @param string The path of the connection * @param int The port that the connection is listening on * @param int The timeout value for the connection * @param string The user name, if authentication is required * @param string The password, if authentication is required */ function setConnection($host, $path = '/', $port = 80, $timeout = 0, $user = null, $password = null) { require_once(DOMIT_INCLUDE_PATH . 'php_http_client_generic.php'); $this->httpConnection = new php_http_client_generic($host, $path, $port, $timeout, $user, $password); } //setConnection /** * Specifies basic authentication for an http connection * @param string The user name * @param string The password */ function setAuthorization($user, $password) { $this->httpConnection->setAuthorization($user, $password); } //setAuthorization /** * Specifies that a proxy is to be used to obtain the xml data * @param string The ip address or domain name of the proxy * @param string The path to the proxy * @param int The port that the proxy is listening on * @param int The timeout value for the connection * @param string The user name, if authentication is required * @param string The password, if authentication is required */ function setProxyConnection($host, $path = '/', $port = 80, $timeout = 0, $user = null, $password = null) { require_once(DOMIT_INCLUDE_PATH . 'php_http_proxy.php'); $this->httpConnection = new php_http_proxy($host, $path, $port, $timeout, $user, $password); } //setProxyConnection /** * Specifies basic authentication for the proxy * @param string The user name * @param string The password */ function setProxyAuthorization($user, $password) { $this->httpConnection->setProxyAuthorization($user, $password); } //setProxyAuthorization /** * Specifies whether an HTTP client should be used to establish a connection * @param boolean True if an HTTP client is to be used to establish the connection */ function useHTTPClient($truthVal) { $this->doUseHTTPClient = $truthVal; } //useHTTPClient /** * Returns the error code from the underlying SAX parser * @return int The error code */ function getErrorCode() { return $this->errorCode; } //getErrorCode /** * Returns the error string from the underlying SAX parser * @return string The error string */ function getErrorString() { return $this->errorString; } //getErrorString /** * Specifies whether elements tags will be rendered to string as <element></element> rather than <element/> * @param boolean True if the expanded form is to be used * @param mixed An array of tag names that should be excepted from expandEmptyElements rule (optional) */ function expandEmptyElementTags($truthVal, $expandEmptyElementExceptions = false) { $this->doExpandEmptyElementTags = $truthVal; if (is_array($expandEmptyElementExceptions)) { $this->expandEmptyElementExceptions = $expandEmptyElementExceptions; } } //expandEmptyElementTags /** * Set the specified node as document element * @param Object The node that is to become document element * @return Object The new document element */ function &setDocumentElement(&$node) { if ($node->nodeType == DOMIT_ELEMENT_NODE) { if ($this->documentElement == null) { parent::appendChild($node); } else { parent::replaceChild($node, $this->documentElement); } $this->documentElement =& $node; } else { DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR, ('Cannot add a node of type ' . get_class($node) . ' as a Document Element.')); } return $node; } //setDocumentElement /** * Imports a node (and optionally its children) from another DOM Document * @param object A reference to the node to be imported * @param boolean True if the children of the imported node are also to be imported * @return object The imported node (and, if specified, its children) */ function &importNode(&$importedNode, $deep = true) { $parentNode = null; return $this->_importNode($parentNode, $importedNode, $deep); } //importNode /** * Imports a node (and optionally its children) from another DOM Document * @param object A reference to the parent of the node to be imported * @param object A reference to the node to be imported * @param boolean True if the children of the imported node are also to be imported * @return object The imported node if it is the top level node, otherwise null */ function &_importNode(&$parentNode, &$sourceNode, $deep) { $hasChildren = false; switch ($sourceNode->nodeType) { case DOMIT_ELEMENT_NODE: $hasChildren = true; if ($this->isNamespaceAware) { $importedNode =& $this->createElementNS($sourceNode->namespaceURI, ($sourceNode->prefix . ":" . $sourceNode->localName)); } else { $importedNode =& $this->createElement($sourceNode->nodeName); } $attrNodes =& $sourceNode->attributes; $total = $attrNodes->getLength(); for ($i = 0; $i < $total; $i++) { $attrNode =& $attrNodes->item($i); if ($this->isNamespaceAware) { $importedNode->setAttributeNS($attrNode->namespaceURI, ($attrNode->prefix . ":" . $attrNode->localName), $attrNode->nodeValue); } else { $importedNode->setAttribute($attrNode->nodeName, $attrNode->nodeValue); } } break; case DOMIT_ATTRIBUTE_NODE: if ($this->isNamespaceAware) { $importedNode =& $this->createAttributeNS($sourceNode->namespaceURI, ($sourceNode->prefix . ":" . $sourceNode->localName)); } else { $importedNode =& $this->createAttribute($sourceNode->nodeValue); } break; case DOMIT_TEXT_NODE: $importedNode =& $this->createTextNode($sourceNode->nodeValue); break; case DOMIT_CDATA_SECTION_NODE: $importedNode =& $this->createCDATASection($sourceNode->nodeValue); break; case DOMIT_COMMENT_NODE: $importedNode =& $this->createComment($sourceNode->nodeValue); break; case DOMIT_DOCUMENT_FRAGMENT_NODE: $hasChildren = true; $importedNode =& $this->createDocumentFragment(); break; case DOMIT_PROCESSING_INSTRUCTION_NODE: $importedNode =& $this->createProcessingInstruction($sourceNode->nodeName, $sourceNode->nodeValue); break; case DOMIT_DOCUMENT_NODE: case DOMIT_DOCUMENT_TYPE_NODE: DOMIT_DOMException::raiseException(DOMIT_NOT_SUPPORTED_ERR, ('Method importNode cannot be called by class ' . get_class($this))); break; } if ($hasChildren && $deep) { $total = $sourceNode->childCount; for ($i = 0; $i < $total; $i++) { $importedNode->appendChild( $this->_importNode($importedNode, $sourceNode->childNodes[$i], $deep)); } } return $importedNode; } //_importNode /** * Appends a node to the childNodes list of the current node * @param Object The node to be appended * @return Object The appended node */ function &appendChild(&$node) { switch ($node->nodeType) { case DOMIT_ELEMENT_NODE: if ($this->documentElement == null) { parent::appendChild($node); $this->setDocumentElement($node); } else { //error thrown if documentElement already exists! DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR, ('Cannot have more than one root node (documentElement) in a DOMIT_Document.')); } break; case DOMIT_PROCESSING_INSTRUCTION_NODE: case DOMIT_COMMENT_NODE: parent::appendChild($node); break; case DOMIT_DOCUMENT_TYPE_NODE: if ($this->doctype == null) { parent::appendChild($node); } else { DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR, ('Cannot have more than one doctype node in a DOMIT_Document.')); } break; case DOMIT_DOCUMENT_FRAGMENT_NODE: $total = $node->childCount; for ($i = 0; $i < $total; $i++) { $currChild =& $node->childNodes[$i]; $this->appendChild($currChild); } break; default: DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR, ('Cannot add a node of type ' . get_class($node) . ' to a DOMIT_Document.')); } return $node; } //appendChild /** * Replaces a node with another * @param Object The new node * @param Object The old node * @return Object The new node */ function &replaceChild(&$newChild, &$oldChild) { if ($this->nodeType == DOMIT_DOCUMENT_FRAGMENT_NODE) { $total = $newChild->childCount; if ($total > 0) { $newRef =& $newChild->lastChild; $this->replaceChild($newRef, $oldChild); for ($i = 0; $i < ($total - 1); $i++) { $currChild =& $newChild->childNodes[$i]; parent::insertBefore($currChild, $newRef); } } } else { if (($this->documentElement != null) && ($oldChild->uid == $this->documentElement->uid)) { if ($newChild->nodeType == DOMIT_ELEMENT_NODE) { //replace documentElement with new node $this->setDocumentElement($newChild); } else { DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR, ('Cannot replace Document Element with a node of class ' . get_class($newChild))); } } else { switch ($newChild->nodeType) { case DOMIT_ELEMENT_NODE: if ($this->documentElement != null) { DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR, ('Cannot have more than one root node (documentElement) in a DOMIT_Document.')); } else { parent::replaceChild($newChild, $oldChild); } break; case DOMIT_PROCESSING_INSTRUCTION_NODE: case DOMIT_COMMENT_NODE: parent::replaceChild($newChild, $oldChild); break; case DOMIT_DOCUMENT_TYPE_NODE: if ($this->doctype != null) { if ($this->doctype->uid == $oldChild->uid) { parent::replaceChild($newChild, $oldChild); } else { DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR, ('Cannot have more than one doctype node in a DOMIT_Document.')); } } else { parent::replaceChild($newChild, $oldChild); } break; default: DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR, ('Nodes of class ' . get_class($newChild) . ' cannot be children of a DOMIT_Document.')); } } } return $newChild; } //replaceChild /** * Inserts a node to the childNodes list of the current node * @param Object The node to be inserted * @param Object The node before which the insertion is to occur * @return Object The inserted node */ function &insertBefore(&$newChild, &$refChild) { $type = $newChild->nodeType; if ($this->nodeType == DOMIT_DOCUMENT_FRAGMENT_NODE) { $total = $newChild->childCount; for ($i = 0; $i < $total; $i++) { $currChild =& $newChild->childNodes[$i]; $this->insertBefore($currChild, $refChild); } } else if ($type == DOMIT_ELEMENT_NODE) { if ($this->documentElement == null) { parent::insertBefore($newChild, $refChild); $this->setDocumentElement($newChild); } else { //error thrown if documentElement already exists! DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR, ('Cannot have more than one root node (documentElement) in a DOMIT_Document.')); } } else if ($type == DOMIT_PROCESSING_INSTRUCTION_NODE) { parent::insertBefore($newChild, $refChild); } else if ($type == DOMIT_DOCUMENT_TYPE_NODE) { if ($this->doctype == null) { parent::insertBefore($newChild, $refChild); } else { DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR, ('Cannot have more than one doctype node in a DOMIT_Document.')); } } else { DOMIT_DOMException::raiseException(DOMIT_HIERARCHY_REQUEST_ERR, ('Cannot insert a node of type ' . get_class($newChild) . ' to a DOMIT_Document.')); } return $newChild; } //insertBefore /** * Removes a node from the childNodes list of the current node * @param Object The node to be removed * @return Object The removed node */ function &removeChild(&$oldChild) { if ($this->nodeType == DOMIT_DOCUMENT_FRAGMENT_NODE) { $total = $oldChild->childCount; for ($i = 0; $i < $total; $i++) { $currChild =& $oldChild->childNodes[$i]; $this->removeChild($currChild); } } else { if (($this->documentElement != null) && ($oldChild->uid == $this->documentElement->uid)) { parent::removeChild($oldChild); $this->documentElement = null; } else { parent::removeChild($oldChild); } } $oldChild->clearReferences(); return $oldChild; } //removeChild /** * Creates a new DOMIT_DocumentFragment node * @return Object The new document fragment node */ function &createDocumentFragment() { $node = new DOMIT_DocumentFragment(); $node->ownerDocument =& $this; return $node; } //createDocumentFragment /** * Creates a new DOMIT_Attr node * @param string The name of the attribute * @return Object The new attribute node */ function &createAttribute($name) { $node = new DOMIT_Attr($name); return $node; } //createAttribute /** * Creates a new DOMIT_Attr node (namespace aware) * @param string The namespaceURI of the attribute * @param string The qualifiedName of the attribute * @return Object The new attribute node */ function &createAttributeNS($namespaceURI, $qualifiedName) { $node = new DOMIT_Attr($qualifiedName); $node->namespaceURI = $namespaceURI; $colonIndex = strpos($qualifiedName, ":"); if ($colonIndex !== false) { $node->prefix = substr($qualifiedName, 0, $colonIndex); $node->localName = substr($qualifiedName, ($colonIndex + 1)); } else { $node->prefix = ''; $node->localName = $qualifiedName; } return $node; } //createAttributeNS /** * Creates a new DOMIT_Element node * @param string The tag name of the element * @return Object The new element */ function &createElement($tagName) { $node = new DOMIT_Element($tagName); $node->ownerDocument =& $this; return $node; } //createElement /** * Creates a new DOMIT_Element node (namespace aware) * @param string The namespaceURI of the element * @param string The qualifiedName of the element * @return Object The new element */ function &createElementNS($namespaceURI, $qualifiedName) { $node = new DOMIT_Element($qualifiedName); $colonIndex = strpos($qualifiedName, ":"); if ($colonIndex !== false) { $node->prefix = substr($qualifiedName, 0, $colonIndex); $node->localName = substr($qualifiedName, ($colonIndex + 1)); } else { $node->prefix = ''; $node->localName = $qualifiedName; } $node->namespaceURI = $namespaceURI; $node->ownerDocument =& $this; return $node; } //createElementNS /** * Creates a new DOMIT_Text node * @param string The text of the node * @return Object The new text node */ function &createTextNode($data) { $node = new DOMIT_TextNode($data); $node->ownerDocument =& $this; return $node; } //createTextNode /** * Creates a new DOMIT_CDataSection node * @param string The text of the CDATASection * @return Object The new CDATASection node */ function &createCDATASection($data) { $node = new DOMIT_CDATASection($data); $node->ownerDocument =& $this; return $node; } //createCDATASection /** * Creates a new DOMIT_Comment node * @param string The comment text * @return Object The new comment node */ function &createComment($text) { $node = new DOMIT_Comment($text); $node->ownerDocument =& $this; return $node; } //createComment /** * Creates a new DOMIT_ProcessingInstruction node * @param string The target of the processing instruction * @param string The data of the processing instruction * @return Object The new processing instruction node */ function &createProcessingInstruction($target, $data) { $node = new DOMIT_ProcessingInstruction($target, $data); $node->ownerDocument =& $this; return $node; } //createProcessingInstruction /** * Retrieves a NodeList of child elements with the specified tag name * @param string The matching element tag name * @return Object A NodeList of found elements */ function &getElementsByTagName($tagName) { $nodeList = new DOMIT_NodeList(); if ($this->documentElement != null) { $this->documentElement->getNamedElements($nodeList, $tagName); } return $nodeList; } //getElementsByTagName /** * Retrieves a NodeList of child elements with the specified namespaceURI and localName * @param string The matching namespaceURI * @param string The matching localName * @return Object A NodeList of found elements */ function &getElementsByTagNameNS($namespaceURI, $localName) { $nodeList = new DOMIT_NodeList(); if ($this->documentElement != null) { $this->documentElement->getNamedElementsNS($nodeList, $namespaceURI, $localName); } return $nodeList; } //getElementsByTagNameNS /** * Returns the element whose ID is given by elementId. * @param string The id of the matching element * @param boolean True if XML spec is to be strictly adhered to (only attributes xml:id are considered valid) * @return Object The found element or null */ function &getElementByID($elementID, $isStrict = true) { if ($this->isNamespaceAware) { if ($this->documentElement != null) { $targetAttrNode =& $this->documentElement->_getElementByID($elementID, $isStrict); return $targetAttrNode->ownerElement; } $null = null; return $null; } else { DOMIT_DOMException::raiseException(DOMIT_INVALID_ACCESS_ERR, 'Namespace awareness must be enabled to use method getElementByID'); } } //getElementByID /** * Retrieves an element or DOMIT_NodeList of elements corresponding to an Xpath-like expression. * @param string The query pattern * @param int If a single node is to be returned (rather than the entire NodeList) the index of that node * @return mixed A NodeList or single node that matches the pattern */ function &getElementsByPath($pattern, $nodeIndex = 0) { require_once(DOMIT_INCLUDE_PATH . 'xml_domit_getelementsbypath.php'); $gebp = new DOMIT_GetElementsByPath(); $myResponse =& $gebp->parsePattern($this, $pattern, $nodeIndex); return $myResponse; } //getElementsByPath /** * Retrieves an element or DOMIT_NodeList of elements corresponding to an Xpath-like attribute expression (NOT YET IMPLEMENTED!) * @param string The query pattern * @param int If a single node is to be returned (rather than the entire NodeList) the index of that node * @return mixed A NodeList or single node that matches the pattern */ function &getElementsByAttributePath($pattern, $nodeIndex = 0) { require_once(DOMIT_INCLUDE_PATH . 'xml_domit_getelementsbypath.php'); $gabp = new DOMIT_GetElementsByAttributePath(); $myResponse =& $gabp->parsePattern($this, $pattern, $nodeIndex); return $myResponse; } //getElementsByAttributePath /** * Retrieves all child nodes of the specified nodeType * @param string The nodeType of matching nodes * @param Object The root node of the search * @return Object A NodeList containing found nodes */ function &getNodesByNodeType($type, &$contextNode) { $nodeList = new DOMIT_NodeList(); if (($type == DOMIT_DOCUMENT_NODE) || ($contextNode->nodeType == DOMIT_DOCUMENT_NODE)){ $nodeList->appendNode($this); } else if ($contextNode->nodeType == DOMIT_ELEMENT_NODE) { $contextNode->getTypedNodes($nodeList, $type); } else if ($contextNode->uid == $this->uid) { if ($this->documentElement != null) { if ($type == DOMIT_ELEMENT_NODE) { $nodeList->appendNode($this->documentElement); } $this->documentElement->getTypedNodes($nodeList, $type); } } return $nodeList; } //getNodesByNodeType /** * Retrieves all child nodes of the specified nodeValue * @param string The nodeValue of matching nodes * @param Object The root node of the search * @return Object A NodeList containing found nodes */ function &getNodesByNodeValue($value, &$contextNode) { $nodeList = new DOMIT_NodeList(); if ($contextNode->uid == $this->uid) { if ($this->nodeValue == $value) { $nodeList->appendNode($this); } } if ($this->documentElement != null) { $this->documentElement->getValuedNodes($nodeList, $value); } return $nodeList; } //getNodesByNodeValue /** * Parses an xml string * @param string The xml text to be parsed * @param boolean True if SAXY is to be used instead of Expat * @param boolean False if CDATA Section are to be generated as Text nodes * @param boolean True if onLoad is to be called on each node after parsing * @return boolean True if parsing is successful */ function parseXML($xmlText, $useSAXY = true, $preserveCDATA = true, $fireLoadEvent = false) { require_once(DOMIT_INCLUDE_PATH . 'xml_domit_utilities.php'); if ($this->doResolveErrors) { require_once(DOMIT_INCLUDE_PATH . 'xml_domit_doctor.php'); $xmlText = DOMIT_Doctor::fixAmpersands($xmlText); } if (DOMIT_Utilities::validateXML($xmlText)) { $domParser = new DOMIT_Parser(); if ($useSAXY || (!function_exists('xml_parser_create'))) { //use SAXY parser to populate xml tree $this->parser = 'SAXY'; $success = $domParser->parseSAXY($this, $xmlText, $preserveCDATA, $this->definedEntities); } else { //use Expat parser to populate xml tree $this->parser = 'EXPAT'; $success = $domParser->parse($this, $xmlText, $preserveCDATA); } if ($fireLoadEvent && ($this->documentElement != null)) $this->load($this->documentElement); return $success; } else { return false; } } //parseXML /** * Parses an xml file * @param string The xml file to be parsed * @param boolean True if SAXY is to be used instead of Expat * @param boolean False if CDATA Section are to be generated as Text nodes * @param boolean True if onLoad is to be called on each node after parsing * @return boolean True if parsing is successful */ function loadXML($filename, $useSAXY = true, $preserveCDATA = true, $fireLoadEvent = false) { $xmlText = $this->getTextFromFile($filename); return $this->parseXML($xmlText, $useSAXY, $preserveCDATA, $fireLoadEvent); } //loadXML /** * Establishes a connection, given an url * @param string The url of the data */ function establishConnection($url) { require_once(DOMIT_INCLUDE_PATH . 'php_http_client_generic.php'); $host = php_http_connection::formatHost($url); $host = substr($host, 0, strpos($host, '/')); $this->setConnection($host); } //establishConnection /** * Retrieves text from a file * @param string The file path * @return string The text contained in the file */ function getTextFromFile($filename) { if ($this->doUseHTTPClient && (substr($filename, 0, 5) == 'http:')) { $this->establishConnection($filename); } if ($this->httpConnection != null) { $response =& $this->httpConnection->get($filename); $this->httpConnection->disconnect(); return $response->getResponse(); } else if (function_exists('file_get_contents')) { //if (file_exists($filename)) { return file_get_contents($filename); //} } else { require_once(DOMIT_INCLUDE_PATH . 'php_file_utilities.php'); $fileContents =& php_file_utilities::getDataFromFile($filename, 'r'); return $fileContents; } return ''; } //getTextFromFile /** * Saves the current DOM document as an xml file * @param string The path of the xml file * @param boolean True if xml text is to be normalized before saving * @return boolean True if save is successful */ function saveXML($filename, $normalized = false) { if ($normalized) { $stringRep = $this->toNormalizedString(false, true); } else { $stringRep = $this->toString(false, true); } return $this->saveTextToFile($filename, $stringRep); } //saveXML /** * Saves text to a file * @param string The file path * @param string The text to be saved * @return boolean True if the save is successful */ function saveTextToFile($filename, $text) { if (function_exists('file_put_contents')) { file_put_contents($filename, $text); } else { require_once(DOMIT_INCLUDE_PATH . 'php_file_utilities.php'); php_file_utilities::putDataToFile($filename, $text, 'w'); } return (file_exists($filename) && is_writable($filename)); } //saveTextToFile /** * Indicates the SAX parser used to parse the current document * @return string Either "SAXY" or "EXPAT" */ function parsedBy() { return $this->parser; } //parsedBy /** * Returns the concatented text of the current node and its children * @return string The concatented text of the current node and its children */ function getText() { if ($this->documentElement != null) { $root =& $this->documentElement; return $root->getText(); } return ''; } //getText /** * Returns a doctype object * @return mixed The doctype object, or null if none exists */ function getDocType() { return $this->doctype; } //getDocType /** * Returns the xml declaration processing instruction * @return mixed The xml declaration processing instruction, or null if none exists */ function getXMLDeclaration() { return $this->xmlDeclaration; } //getXMLDeclaration /** * Returns a reference to the DOMIT_DOMImplementation object * @return Object A reference to the DOMIT_DOMImplementation object */ function &getDOMImplementation() { return $this->implementation; } //getDOMImplementation /** * Manages the firing of the onLoad() event * @param Object The parent node of the current recursion */ function load(&$contextNode) { $total = $contextNode->childCount; for ($i = 0; $i < $total; $i++) { $currNode =& $contextNode->childNodes[$i]; $currNode->ownerDocument->load($currNode); } $contextNode->onLoad(); } //load /** * Returns the current version of DOMIT! * @return Object The current version of DOMIT! */ function getVersion() { return DOMIT_VERSION; } //getVersion /** * Appends an array of entity mappings to the existing translation table * * Intended mainly to facilitate the conversion of non-ASCII entities into equivalent characters * * @param array A list of entity mappings in the format: array('&amp;' => '&'); */ function appendEntityTranslationTable($table) { $this->definedEntities = $table; global $DOMIT_defined_entities_flip; $DOMIT_defined_entities_flip = array_flip($table); } //appendEntityTranslationTable /** * Generates an array representation of the node and its children * @return Array A representation of the node and its children */ function toArray() { $arReturn = array($this->nodeName => array()); $total = $this->childCount; for ($i = 0; $i < $total; $i++) { $arReturn[$this->nodeName][$i] = $this->childNodes[$i]->toArray(); } return $arReturn; } //toArray /** * Copies a node and/or its children * @param boolean True if all child nodes are also to be cloned * @return Object A copy of the node and/or its children */ function &cloneNode($deep = false) { $className = get_class($this); $clone = new $className($this->nodeName); if ($deep) { $total = $this->childCount; for ($i = 0; $i < $total; $i++) { $currentChild =& $this->childNodes[$i]; $clone->appendChild($currentChild->cloneNode($deep)); if ($currentChild->nodeType == DOMIT_DOCUMENT_TYPE_NODE) { $clone->doctype =& $clone->childNodes[$i]; } if (($currentChild->nodeType == DOMIT_PROCESSING_INSTRUCTION_NODE) && ($currentChild->getTarget() == 'xml')) { $clone->xmlDeclaration =& $clone->childNodes[$i]; } } } return $clone; } //cloneNode /** * Generates a string representation of the node and its children * @param boolean True if HTML readable output is desired * @param boolean True if illegal xml characters in text nodes and attributes should be converted to entities * @return string The string representation */ function toString($htmlSafe = false, $subEntities = false) { $result = ''; $total = $this->childCount; for ($i = 0; $i < $total; $i++) { $result .= $this->childNodes[$i]->toString(false, $subEntities); } if ($htmlSafe) $result = $this->forHTML($result); return $result; } //toString } //DOMIT_Document /** * A class representing the DOM Element * * @package domit-xmlparser * @subpackage domit-xmlparser-main * @author John Heinstein <johnkarl@nbnet.nb.ca> */ class DOMIT_Element extends DOMIT_ChildNodes_Interface { /** @var array An array of namespacesURIs mapped to prefixes */ var $namespaceURIMap = array(); /** * DOM Element constructor * @param string The tag name of the element */ function DOMIT_Element($tagName) { $this->_constructor(); $this->nodeType = DOMIT_ELEMENT_NODE; $this->nodeName = $tagName; $this->attributes = new DOMIT_NamedNodeMap_Attr(); $this->childNodes = array(); } //DOMIT_Element /** * Returns the tag name of the element * @return string The tag name of the element */ function getTagName() { return $this->nodeName; } //getTagName /** * Adds elements with the specified tag name to a NodeList collection * @param Object The NodeList collection * @param string The tag name of matching elements */ function getNamedElements(&$nodeList, $tagName) { if (($this->nodeName == $tagName) || ($tagName == '*')) { $nodeList->appendNode($this); } $total = $this->childCount; for ($i = 0; $i < $total; $i++) { $this->childNodes[$i]->getNamedElements($nodeList, $tagName); } } //getNamedElements /** * Creates an xmlns declaration at the current element * @param array An array of namespace declarations in the scope of the current element */ function declareNamespace($localname, $value) { //namespace URI for xmlns attribute is: http://www.w3.org/2000/xmlns/ $this->setAttributeNS(DOMIT_XMLNS_NAMESPACE, ('xmlns:' . $localname), $value); //add to local namespaceURI map $this->namespaceURIMap[$value] = $localname; } //declareNamespace /** * Creates a default xmlns declaration at the current element * @param array An array of namespace declarations in the scope of the current element */ function declareDefaultNamespace($value) { //namespace URI for xmlns attribute is: http://www.w3.org/2000/xmlns/ $this->setAttributeNS(DOMIT_XMLNS_NAMESPACE, 'xmlns', $value); //add to local namespaceURI map $this->namespaceURIMap[$value] = 'xmlns'; } //declareDefaultNamespace /** * Returns an array of namespace declarations in the scope of the current element * @return array An array of namespace declarations in the scope of the current element */ function &getNamespaceDeclarationsInScope() { $nsMap = array(); return $this->_getNameSpaceDeclarationsInScope($nsMap); } //getNamespacesInScope /** * Returns an array of namespace declarations in the scope of the current element * @return array An array of namespace declarations in the scope of the current element */ function &_getNamespaceDeclarationsInScope(&$nsMap) { //grab local xmlns declarations if not already present foreach ($this->namespaceURIMap as $key => $value) { if (!isset($nsMap[$key])) { $nsMap[$key] = $value; } } //move up the tree if not already at the top if ($this->parentNode->uid != $this->ownerDocument->uid) { $this->parentNode->_getNamespaceDeclarationsInScope($nsMap); } return $nsMap; } //_getNamespacesInScope /** * Returns the default xmlns declaration for the current element * @return string The default xmlns declaration for the current element */ function getDefaultNamespaceDeclaration() { if (in_array('xmlns', $this->namespaceURIMap)) { foreach ($this->namespaceURIMap as $key => $value) { if ($value == 'xmlns') { return $key; } } } else if ($this->parentNode->uid != $this->ownerDocument->uid) { return $this->parentNode->getDefaultNamespaceDeclaration(); } else { return ''; } } //getDefaultNamespaceDeclaration /** * Copies all namespace declarations in scope to the namespace URI map of the current element */ function copyNamespaceDeclarationsLocally() { $nsMap = $this->getNamespaceDeclarationsInScope(); //add xmlns declarations as attributes foreach ($nsMap as $key => $value) { if ($value == 'xmlns') { $this->declareDefaultNamespace($key); } else { $this->declareNamespace($value, $key); } } } //copyNamespaceDeclarationsLocally /** * Adds elements with the specified tag name to a NodeList collection * @param Object The NodeList collection * @param string The namespaceURI of matching elements * @param string The localName of matching elements */ function getNamedElementsNS(&$nodeList, $namespaceURI, $localName) { if ((($namespaceURI == $this->namespaceURI) || ($namespaceURI == '*')) && (($localName == $this->localName) || ($localName == '*'))) { $nodeList->appendNode($this); } $total = $this->childCount; for ($i = 0; $i < $total; $i++) { if ($this->childNodes[$i]->nodeType == DOMIT_ELEMENT_NODE) { $this->childNodes[$i]->getNamedElementsNS($nodeList, $namespaceURI, $localName); } } } //getNamedElementsNS /** * Returns the concatented text of the current node and its children * @return string The concatented text of the current node and its children */ function getText() { $text = ''; $numChildren = $this->childCount; for ($i = 0; $i < $numChildren; $i++) { $child =& $this->childNodes[$i]; $text .= $child->getText(); } return $text; } //getText /** * If a child text node exists, sets the nodeValue to $data. A child text node is created if none exists * @param string The text data of the node */ function setText($data) { switch ($this->childCount) { case 1: if ($this->firstChild->nodeType == DOMIT_TEXT_NODE) { $this->firstChild->setText($data); } break; case 0: $childTextNode =& $this->ownerDocument->createTextNode($data); $this->appendChild($childTextNode); break; default: //do nothing. Maybe throw error??? } } //setText /** * Retrieves a NodeList of child elements with the specified tag name * @param string The matching element tag name * @return Object A NodeList of found elements */ function &getElementsByTagName($tagName) { $nodeList = new DOMIT_NodeList(); $this->getNamedElements($nodeList, $tagName); return $nodeList; } //getElementsByTagName /** * Retrieves a NodeList of child elements with the specified namespaceURI and localName * @param string The namespaceURI * @param string The localName * @return Object A NodeList of found elements */ function &getElementsByTagNameNS($namespaceURI, $localName) { $nodeList = new DOMIT_NodeList(); $this->getNamedElementsNS($nodeList, $namespaceURI, $localName); return $nodeList; } //getElementsByTagNameNS /** * Returns the attribute node whose ID is given by elementId. * @param string The id of the matching element * @param boolean True if XML spec is to be strictly adhered to (only attributes xml:id are considered valid) * @return Object The found attribute or null */ function &_getElementByID($elementID, $isStrict) { if ($isStrict) { $myAttrNode =& $this->getAttributeNodeNS(DOMIT_XML_NAMESPACE, 'id'); if (($myAttrNode != null)&& ($myAttrNode->getValue() == $elementID)) return $myAttrNode; } else { $myAttrNode =& $this->getAttributeNodeNS('', 'ID'); if (($myAttrNode != null)&& ($myAttrNode->getValue() == $elementID)) return $myAttrNode; $myAttrNode =& $this->getAttributeNodeNS('', 'id'); if (($myAttrNode != null)&& ($myAttrNode->getValue() == $elementID)) return $myAttrNode; } $total = $this->childCount; for ($i = 0; $i < $total; $i++) { if ($this->childNodes[$i]->nodeType == DOMIT_ELEMENT_NODE) { $foundNode =& $this->childNodes[$i]->_getElementByID($elementID, $isStrict); if ($foundNode != null) { return $foundNode; } } } $null = null; return $null; } //_getElementByID /** * Retrieves an element or DOMIT_NodeList of elements corresponding to an Xpath-like expression. * @param string The query pattern * @param int If a single node is to be returned (rather than the entire NodeList) the index of that node * @return mixed A NodeList or single node that matches the pattern */ function &getElementsByPath($pattern, $nodeIndex = 0) { require_once(DOMIT_INCLUDE_PATH . 'xml_domit_getelementsbypath.php'); $gebp = new DOMIT_GetElementsByPath(); $myResponse =& $gebp->parsePattern($this, $pattern, $nodeIndex); return $myResponse; } //getElementsByPath /** * Retrieves an element or DOMIT_NodeList of elements corresponding to an Xpath-like attribute expression (NOT YET IMPLEMENTED!) * @param string The query pattern * @param int If a single node is to be returned (rather than the entire NodeList) the index of that node * @return mixed A NodeList or single node that matches the pattern */ function &getElementsByAttributePath($pattern, $nodeIndex = 0) { require_once(DOMIT_INCLUDE_PATH . 'xml_domit_getelementsbypath.php'); $gabp = new DOMIT_GetElementsByAttributePath(); $myResponse =& $gabp->parsePattern($this, $pattern, $nodeIndex); return $myResponse; } //getElementsByAttributePath /** * Adds all child nodes of the specified nodeType to the NodeList * @param Object The NodeList collection * @param string The nodeType of matching nodes */ function getTypedNodes(&$nodeList, $type) { $numChildren = $this->childCount; for ($i = 0; $i < $numChildren; $i++) { $child =& $this->childNodes[$i]; if ($child->nodeType == $type) { $nodeList->appendNode($child); } if ($child->hasChildNodes()) { $child->getTypedNodes($nodeList, $type); } } } //getTypedNodes /** * Adds all child nodes of the specified nodeValue to the NodeList * @param Object The NodeList collection * @param string The nodeValue of matching nodes */ function getValuedNodes(&$nodeList, $value) { $numChildren = $this->childCount; for ($i = 0; $i < $numChildren; $i++) { $child =& $this->childNodes[$i]; if ($child->nodeValue == $value) { $nodeList->appendNode($child); } if ($child->hasChildNodes()) { $child->getValuedNodes($nodeList, $value); } } } //getValuedNodes /** * Gets the value of the specified attribute, if it exists * @param string The attribute name * @return string The attribute value */ function getAttribute($name) { $returnNode =& $this->attributes->getNamedItem($name); if ($returnNode == null) { return ''; } else { return $returnNode->getValue(); } } //getAttribute /** * Gets the value of the attribute with the specified namespaceURI and localName, if it exists * @param string The namespaceURI * @param string The localName * @return string The attribute value */ function getAttributeNS($namespaceURI, $localName) { $returnNode =& $this->attributes->getNamedItemNS($namespaceURI, $localName); if ($returnNode == null) { return ''; } else { return $returnNode->getValue(); } } //getAttributeNS /** * Sets the value of the specified attribute; creates a new attribute if one doesn't exist * @param string The attribute name * @param string The desired attribute value */ function setAttribute($name, $value) { $returnNode =& $this->attributes->getNamedItem($name); if ($returnNode == null) { $newAttr = new DOMIT_Attr($name); $newAttr->setValue($value); $this->attributes->setNamedItem($newAttr); } else { $returnNode->setValue($value); } } //setAttribute /** * Sets the value of the specified attribute; creates a new attribute if one doesn't exist * @param string The attribute namespaceURI * @param string The attribute qualifiedName * @param string The desired attribute value */ function setAttributeNS($namespaceURI, $qualifiedName, $value) { //get localName $colonIndex = strpos($qualifiedName, ":"); if ($colonIndex !== false) { $localName = substr($qualifiedName, ($colonIndex + 1)); } else { $localName = $qualifiedName; } $returnNode =& $this->attributes->getNamedItemNS($namespaceURI, $localName); if ($returnNode == null) { //create this manually in case element has no ownerDocument to reference $newAttr = new DOMIT_Attr($qualifiedName); $newAttr->prefix = substr($qualifiedName, 0, $colonIndex); $newAttr->localName = $localName; $newAttr->namespaceURI = $namespaceURI; $newAttr->setValue($value); $this->attributes->setNamedItemNS($newAttr); $newAttr->ownerElement =& $this; } else { $returnNode->setValue($value); } } //setAttributeNS /** * Removes the specified attribute * @param string The name of the attribute to be removed */ function removeAttribute($name) { $returnNode =& $this->attributes->removeNamedItem($name); } //removeAttribute /** * Removes the specified attribute * @param string The namespaceURI of the attribute to be removed * @param string The localName of the attribute to be removed */ function removeAttributeNS($namespaceURI, $localName) { $returnNode =& $this->attributes->removeNamedItemNS($namespaceURI, $localName); unset($returnNode->ownerElement); $returnNode->ownerElement = null; } //removeAttributeNS /** * Determines whether an attribute with the specified name exists * @param string The name of the attribute * @return boolean True if the attribute exists */ function hasAttribute($name) { $returnNode =& $this->attributes->getNamedItem($name); return ($returnNode != null); } //hasAttribute /** * Determines whether an attribute with the specified namespaceURI and localName exists * @param string The namespaceURI of the attribute * @param string The localName of the attribute * @return boolean True if the attribute exists */ function hasAttributeNS($namespaceURI, $localName) { $returnNode =& $this->attributes->getNamedItemNS($namespaceURI, $localName); return ($returnNode != null); } //hasAttributeNS /** * Determines whether the element has any atributes * @return boolean True if the element has any atributes */ function hasAttributes() { return ($this->attributes->getLength() > 0); } //hasChildNodes /** * Gets a reference to the specified attribute node * @param string The attribute name * @return Object A reference to the found node, or null */ function &getAttributeNode($name) { $returnNode =& $this->attributes->getNamedItem($name); return $returnNode; } //getAttributeNode /** * Gets a reference to the specified attribute node * @param string The attribute namespaceURI * @param string The attribute localName * @return Object A reference to the found node, or null */ function &getAttributeNodeNS($namespaceURI, $localName) { $returnNode =& $this->attributes->getNamedItemNS($namespaceURI, $localName); return $returnNode; } //getAttributeNodeNS /** * Adds an attribute node to the current element * @param Object The attribute node to be added * @return Object A reference to the newly added node */ function &setAttributeNode(&$newAttr) { $returnNode =& $this->attributes->setNamedItem($newAttr); return $returnNode; } //setAttributeNode /** * Adds an attribute node to the current element (namespace aware) * @param Object The attribute node to be added * @return Object A reference to the newly added node */ function &setAttributeNodeNS(&$newAttr) { $returnNode =& $this->attributes->setNamedItemNS($newAttr); $newAttr->ownerElement =& $this; return $returnNode; } //setAttributeNodeNS /** * Removes an attribute node from the current element * @param Object The attribute node to be removed * @return Object A reference to the removed node */ function &removeAttributeNode(&$oldAttr) { $attrName = $oldAttr->getName(); $returnNode =& $this->attributes->removeNamedItem($attrName); if ($returnNode == null) { DOMIT_DOMException::raiseException(DOMIT_NOT_FOUND_ERR, 'Target attribute not found.'); } else { return $returnNode; } } //removeAttributeNode /** * Collapses adjacent text nodes in entire element subtree */ function normalize() { if ($this->hasChildNodes()) { $currNode =& $this->childNodes[0]; while ($currNode->nextSibling != null) { $nextNode =& $currNode->nextSibling; if (($currNode->nodeType == DOMIT_TEXT_NODE) && ($nextNode->nodeType == DOMIT_TEXT_NODE)) { $currNode->nodeValue .= $nextNode->nodeValue; $this->removeChild($nextNode); } else { $currNode->normalize(); } if ($currNode->nextSibling != null) { $currNode =& $currNode->nextSibling; } } } } //normalize /** * Generates an array representation of the node and its children * @return Array A representation of the node and its children */ function toArray() { $arReturn = array($this->nodeName => array("attributes" => $this->attributes->toArray())); $total = $this->childCount; for ($i = 0; $i < $total; $i++) { $arReturn[$this->nodeName][$i] = $this->childNodes[$i]->toArray(); } return $arReturn; } //toArray /** * Copies a node and/or its children * @param boolean True if all child nodes are also to be cloned * @return Object A copy of the node and/or its children */ function &cloneNode($deep = false) { $className = get_class($this); $clone = new $className($this->nodeName); $clone->attributes =& $this->attributes->createClone($deep); if ($this->namespaceURI) { $clone->namespaceURI = $this->namespaceURI; $clone->localName = $this->localName; } if ($deep) { $total = $this->childCount; for ($i = 0; $i < $total; $i++) { $currentChild =& $this->childNodes[$i]; $clone->appendChild($currentChild->cloneNode($deep)); } } return $clone; } //cloneNode /** * Generates a string representation of the node and its children * @param boolean True if HTML readable output is desired * @param boolean True if illegal xml characters in text nodes and attributes should be converted to entities * @return string The string representation */ function toString($htmlSafe = false, $subEntities = false) { $result = '<' . $this->nodeName; $result .= $this->attributes->toString(false, $subEntities); if ($this->ownerDocument->isNamespaceAware) { foreach ($this->namespaceURIMap as $key => $value) { $result .= ' xmlns:' . $value . '="' . $key . '"'; } } //get children $myNodes =& $this->childNodes; $total = count($myNodes); if ($total != 0) { $result .= '>'; for ($i = 0; $i < $total; $i++) { $child =& $myNodes[$i]; $result .= $child->toString(false, $subEntities); } $result .= '</' . $this->nodeName . '>'; } else { if ($this->ownerDocument->doExpandEmptyElementTags) { if (in_array($this->nodeName, $this->ownerDocument->expandEmptyElementExceptions)) { $result .= ' />'; } else { $result .= '></' . $this->nodeName . '>'; } } else { if (in_array($this->nodeName, $this->ownerDocument->expandEmptyElementExceptions)) { $result .= '></' . $this->nodeName . '>'; } else { $result .= ' />'; } } } if ($htmlSafe) $result = $this->forHTML($result); return $result; } //toString } //DOMIT_Element /** * A parent class for Text and CDATA Section nodes * * @package domit-xmlparser * @subpackage domit-xmlparser-main * @author John Heinstein <johnkarl@nbnet.nb.ca> */ class DOMIT_CharacterData extends DOMIT_Node { /** * Prevents direct instantiation of DOMIT_CharacterData class * @abstract */ function DOMIT_CharacterData() { DOMIT_DOMException::raiseException(DOMIT_ABSTRACT_CLASS_INSTANTIATION_ERR, 'Cannot instantiate abstract class DOMIT_CharacterData'); } //DOMIT_CharacterData /** * Gets the node value of the current text node * @return string The node value of the current text node */ function getData() { return $this->nodeValue; } //getData /** * Sets the text contained in the current node to $data. * @param string The text data of the node */ function setData($data) { $this->nodeValue = $data; } //setData /** * Gets the length of the text in the current node * @return int The length of the text in the current node */ function getLength() { return strlen($this->nodeValue); } //getLength /** * Gets a subset of the current node text * @param int The starting point of the substring * @param int The length of the substring * @return string The subset of the current node text */ function substringData($offset, $count) { $totalChars = $this->getLength(); if (($offset < 0) || (($offset + $count) > $totalChars)) { DOMIT_DOMException::raiseException(DOMIT_INDEX_SIZE_ERR, 'Character Data index out of bounds.'); } else { $data = $this->getData(); return substr($data, $offset, $count); } } //substringData /** * Appends the specified text to the current node text * @param string The text to be appended */ function appendData($arg) { $this->setData($this->getData() . $arg); } //appendData /** * Inserts text at the sepecified offset * @param int The insertion point * @param string The text to be inserted */ function insertData($offset, $arg) { $totalChars = $this->getLength(); if (($offset < 0) || ($offset > $totalChars)) { DOMIT_DOMException::raiseException(DOMIT_INDEX_SIZE_ERR, 'Character Data index out of bounds.'); } else { $data = $this->getData(); $pre = substr($data, 0, $offset); $post = substr($data, $offset); $this->setData(($pre . $arg . $post)); } } //insertData /** * Deletes a subset of the current node text * @param int The starting point of the deletion * @param int The length of the deletion */ function deleteData($offset, $count) { $totalChars = $this->getLength(); if (($offset < 0) || (($offset + $count) > $totalChars)) { DOMIT_DOMException::raiseException(DOMIT_INDEX_SIZE_ERR, 'Character Data index out of bounds.'); } else { $data = $this->getData(); $pre = substr($data, 0, $offset); $post = substr($data, ($offset + $count)); $this->setData(($pre . $post)); } } //substringData /** * Replaces a subset of the current node text with the specified text * @param int The starting point of the replacement * @param int The length of the replacement * @param string The replacement text */ function replaceData($offset, $count, $arg) { $totalChars = $this->getLength(); if (($offset < 0) || (($offset + $count) > $totalChars)) { DOMIT_DOMException::raiseException(DOMIT_INDEX_SIZE_ERR, 'Character Data index out of bounds.'); } else { $data = $this->getData(); $pre = substr($data, 0, $offset); $post = substr($data, ($offset + $count)); $this->setData(($pre . $arg . $post)); } } //replaceData } //DOMIT_CharacterData /** * A class representing the DOM Text Node * * @package domit-xmlparser * @subpackage domit-xmlparser-main * @author John Heinstein <johnkarl@nbnet.nb.ca> */ class DOMIT_TextNode extends DOMIT_CharacterData { /** * DOM Text Node constructor * @param string The text of the node */ function DOMIT_TextNode($data) { $this->_constructor(); $this->nodeType = DOMIT_TEXT_NODE; $this->nodeName = '#text'; $this->setText($data); } //DOMIT_TextNode /** * Returns the text contained in the current node * @return string The text of the current node */ function getText() { return $this->nodeValue; } //getText /** * Sets the text contained in the current node to $data. * @param string The text data of the node */ function setText($data) { $this->nodeValue = $data; } //setText /** * Splits a single node into multiple nodes, based on the specified offset * @param int The offset point for the split * @return Object The newly created text node */ function &splitText($offset) { $totalChars = $this->getLength(); if (($offset < 0) || ($offset > $totalChars)) { DOMIT_DOMException::raiseException(DOMIT_INDEX_SIZE_ERR, 'Character Data index out of bounds.'); } else { $data = $this->getData(); $pre = substr($data, 0, $offset); $post = substr($data, $offset); $this->setText($pre); //create new text node $className = get_class($this); $newTextNode = new $className($post); $newTextNode->ownerDocument =& $this->ownerDocument; if ($this->parentNode->lastChild->uid == $this->uid) { $this->parentNode->appendChild($newTextNode); } else { $this->parentNode->insertBefore($newTextNode, $this); } return $newTextNode; } } //splitText /** * Generates an array representation of the node and its children * @return Array A representation of the node and its children */ function toArray() { return $this->toString(); } //toArray /** * Copies a node and/or its children * @param boolean True if all child nodes are also to be cloned * @return Object A copy of the node and/or its children */ function &cloneNode($deep = false) { $className = get_class($this); $clone = new $className($this->nodeValue); return $clone; } //cloneNode /** * Generates a string representation of the node and its children * @param boolean True if HTML readable output is desired * @param boolean True if illegal xml characters should be converted to entities * @return string The string representation */ function toString($htmlSafe = false, $subEntities = false) { require_once(DOMIT_INCLUDE_PATH . 'xml_domit_utilities.php'); global $DOMIT_defined_entities_flip; $result = $subEntities ? DOMIT_Utilities::convertEntities($this->nodeValue, $DOMIT_defined_entities_flip) : $this->nodeValue; if ($htmlSafe) $result = $this->forHTML($result); return $result; } //toString } //DOMIT_TextNode /** * A class representing the DOM CDATA Section * * @package domit-xmlparser * @subpackage domit-xmlparser-main * @author John Heinstein <johnkarl@nbnet.nb.ca> */ class DOMIT_CDATASection extends DOMIT_TextNode { /** * DOM CDATA Section node constructor * @param string The text of the node */ function DOMIT_CDATASection($data) { $this->_constructor(); $this->nodeType = DOMIT_CDATA_SECTION_NODE; $this->nodeName = '#cdata-section'; $this->setText($data); } //DOMIT_CDATASection /** * Generates a string representation of the node and its children * @param boolean True if HTML readable output is desired * @param boolean True if illegal xml characters should be converted to entities * @return string The string representation */ function toString($htmlSafe = false, $subEntities = false) { $result = '<![CDATA['; $result .= $subEntities ? str_replace("]]>", "]]&gt;", $this->nodeValue) : $this->nodeValue; $result .= ']]>'; if ($htmlSafe) $result = $this->forHTML($result); return $result; } //toString } //DOMIT_CDATASection /** * A class representing the Attr node * * @package domit-xmlparser * @subpackage domit-xmlparser-main * @author John Heinstein <johnkarl@nbnet.nb.ca> */ class DOMIT_Attr extends DOMIT_Node { /** @var boolean True if the attribute has been modified since parsing (NOT YET IMPLEMENTED!) */ var $specified = false; /** @var Object A reference to the element to which the attribute is assigned */ var $ownerElement = null; /** * DOM Attr node constructor * @param string The name of the attribute */ function DOMIT_Attr($name) { $this->_constructor(); $this->nodeType = DOMIT_ATTRIBUTE_NODE; $this->nodeName =$name; } //DOMIT_Attr /** * Returns the name of the attribute * @return string The name of the attribute */ function getName() { return $this->nodeName; } //getName /** * Indicates whether an attribute has been modified since parsing * @return boolean True if the node has been modified */ function getSpecified() { return $this->specified; } //getSpecified /** * Returns the value of the attribute * @return string The value of the attribute */ function getValue() { return $this->nodeValue; } //getValue /** * Sets the value of the attribute * @param string The value of the attribute */ function setValue($value) { $this->nodeValue = $value; } //setValue /** * Returns the text contained in the current node * @return string The text of the current node */ function getText() { return $this->nodeValue; } //getText /** * Sets the text contained in the current node to $data. * @param string The text data of the node */ function setText($data) { $this->nodeValue = $data; } //setText /** * Copies a node and/or its children * @param boolean True if all child nodes are also to be cloned * @return Object A copy of the node and/or its children */ function &cloneNode($deep = false) { $className = get_class($this); $clone = new $className($this->nodeName); $clone->nodeValue = $this->nodeValue; if ($this->namespaceURI) { $clone->namespaceURI = $this->namespaceURI; $clone->localName = $this->localName; } return $clone; } //cloneNode /** * Generates a string representation of the node and its children * @param boolean True if HTML readable output is desired * @param boolean True if HTML entities should be substituted * @return string The string representation */ function toString($htmlSafe = false, $subEntities = false) { require_once(DOMIT_INCLUDE_PATH . 'xml_domit_utilities.php'); global $DOMIT_defined_entities_flip; $result = ' ' . $this->nodeName . '="'; $result .= $subEntities ? DOMIT_Utilities::convertEntities($this->nodeValue, $DOMIT_defined_entities_flip) : $this->nodeValue; $result .= '"'; if ($htmlSafe) $result = $this->forHTML($result); return $result; } //toString } //DOMIT_Attr /** * A class representing the DOM Document Fragment node * * @package domit-xmlparser * @subpackage domit-xmlparser-main * @author John Heinstein <johnkarl@nbnet.nb.ca> */ class DOMIT_DocumentFragment extends DOMIT_ChildNodes_Interface { /** * DOM Document Fragment node constructor */ function DOMIT_DocumentFragment() { $this->_constructor(); $this->nodeType = DOMIT_DOCUMENT_FRAGMENT_NODE; $this->nodeName ='#document-fragment'; $this->nodeValue = null; $this->childNodes = array(); } //DOMIT_DocumentFragment /** * Generates an array representation of the node and its children * @return Array A representation of the node and its children */ function toArray() { $arReturn = array(); $total = $this->childCount; for ($i = 0; $i < $total; $i++) { $arReturn[$i] = $this->childNodes[$i]->toArray(); } return $arReturn; } //toArray /** * Copies a node and/or its children * @param boolean True if all child nodes are also to be cloned * @return Object A copy of the node and/or its children */ function &cloneNode($deep = false) { $className = get_class($this); $clone = new $className(); if ($deep) { $total = $this->childCount; for ($i = 0; $i < $total; $i++) { $currentChild =& $this->childNodes[$i]; $clone->appendChild($currentChild->cloneNode($deep)); } } return $clone; } //cloneNode /** * Generates a string representation of the node and its children * @param boolean True if HTML readable output is desired * @return string The string representation */ function toString($htmlSafe = false, $subEntities = false) { //get children $result = ''; $myNodes =& $this->childNodes; $total = count($myNodes); if ($total != 0) { for ($i = 0; $i < $total; $i++) { $child =& $myNodes[$i]; $result .= $child->toString(false, $subEntities); } } if ($htmlSafe) $result = $this->forHTML($result); return $result; } //toString } //DOMIT_DocumentFragment /** * A class representing the DOM Comment node * * @package domit-xmlparser * @subpackage domit-xmlparser-main * @author John Heinstein <johnkarl@nbnet.nb.ca> */ class DOMIT_Comment extends DOMIT_CharacterData { /** * DOM Comment node constructor * @param string The */ function DOMIT_Comment($nodeValue) { $this->_constructor(); $this->nodeType = DOMIT_COMMENT_NODE; $this->nodeName = '#comment'; $this->nodeValue = $nodeValue; } //DOMIT_Comment /** * Returns the text contained in the current node * @return string The text of the current node */ function getText() { return $this->nodeValue; } //getText /** * Sets the text contained in the current node to $data. * @param string The text data of the node */ function setText($data) { $this->nodeValue = $data; } //setText /** * Generates an array representation of the node and its children * @return Array A representation of the node and its children */ function toArray() { return $this->toString(); } //toArray /** * Copies a node and/or its children * @param boolean True if all child nodes are also to be cloned * @return Object A copy of the node and/or its children */ function &cloneNode($deep = false) { $className = get_class($this); $clone = new $className($this->nodeValue); return $clone; } //cloneNode /** * Generates a string representation of the node and its children * @param boolean True if HTML readable output is desired * @return string The string representation */ function toString($htmlSafe = false) { $result = '<!--' . $this->nodeValue . '-->'; if ($htmlSafe) $result = $this->forHTML($result); return $result; } //toString } //DOMIT_Comment /** * A class representing the DOM Processing Instruction node * * @package domit-xmlparser * @subpackage domit-xmlparser-main * @author John Heinstein <johnkarl@nbnet.nb.ca> */ class DOMIT_ProcessingInstruction extends DOMIT_Node { /** * DOM Processing Instruction node constructor * @param string The */ function DOMIT_ProcessingInstruction($target, $data) { $this->_constructor(); $this->nodeType = DOMIT_PROCESSING_INSTRUCTION_NODE; $this->nodeName = $target; $this->nodeValue = $data; } //DOMIT_ProcessingInstruction /** * Returns the processing instruction target * @return string The processing instruction target */ function getTarget() { return $this->nodeName; } //getTarget /** * Returns the processing instruction data * @return string The processing instruction data */ function getData() { return $this->nodeValue; } //getData /** * Returns the text contained in the current node * @return string The text of the current node */ function getText() { return ($this->nodeName . ' ' . $this->nodeValue); } //getText /** * Generates an array representation of the node and its children * @return Array A representation of the node and its children */ function toArray() { return $this->toString(); } //toArray /** * Copies a node and/or its children * @param boolean True if all child nodes are also to be cloned * @return Object A copy of the node and/or its children */ function &cloneNode($deep = false) { $className = get_class($this); $clone = new $className($this->nodeName, $this->nodeValue); return $clone; } //cloneNode /** * Generates a string representation of the node and its children * @param boolean True if HTML readable output is desired * @return string The string representation */ function toString($htmlSafe = false) { $result = '<' . '?' . $this->nodeName . ' ' . $this->nodeValue . '?' . '>'; if ($htmlSafe) $result = $this->forHTML($result); return $result; } //toString } //DOMIT_ProcessingInstruction /** * A class representing the DOM Document Type node * * @package domit-xmlparser * @subpackage domit-xmlparser-main * @author John Heinstein <johnkarl@nbnet.nb.ca> */ class DOMIT_DocumentType extends DOMIT_Node { /** @var string The doctype name */ var $name; /** @var Object True if the entity has been modified since parsing (NOT YET IMPLEMENTED!) */ var $entities; /** @var Object A NodeList of notation nodes (NOT YET IMPLEMENTED!) */ var $notations; /** @var Object A NodeList of elements (NOT YET IMPLEMENTED!) */ var $elements; /** @var string The full text of the doctype */ var $text; /** @var string The public identifier of the external subset */ var $publicID; /** @var string The system identifier of the external subset */ var $systemID; /** @var string The full text of internal subset */ var $internalSubset; /** * DOM Document Type node constructor * @param string The */ function DOMIT_DocumentType($name, $text) { $this->_constructor(); $this->nodeType = DOMIT_DOCUMENT_TYPE_NODE; $this->nodeName = $name; $this->name = $name; $this->entities = null; //implement later $this->notations = null; //implement later $this->elements = null; //implement later $this->text = $text; } //DOMIT_DocumentType /** * Returns the text contained in the current node * @return string The text of the current node */ function getText() { return $this->text; } //getText /** * Returns the name of the doctype node * @return string The name of the doctype node */ function getName() { return $this->name; } //getName /** * Generates an array representation of the node and its children * @return Array A representation of the node and its children */ function toArray() { return $this->toString(); } //toArray /** * Copies a node and/or its children * @param boolean True if all child nodes are also to be cloned * @return Object A copy of the node and/or its children */ function &cloneNode($deep = false) { $className = get_class($this); $clone = new $className($this->nodeName, $this->text); return $clone; } //cloneNode /** * Generates a string representation of the node and its children * @param boolean True if HTML readable output is desired * @return string The string representation */ function toString($htmlSafe = false) { $result = $this->text; if ($htmlSafe) $result = $this->forHTML($result); return $result; } //toString } //DOMIT_DocumentType /** * A class representing the DOM Notation node (NOT YET IMPLEMENTED!) * * @package domit-xmlparser * @subpackage domit-xmlparser-main * @author John Heinstein <johnkarl@nbnet.nb.ca> */ class DOMIT_Notation extends DOMIT_Node { /** * DOM Notation node constructor (NOT YET IMPLEMENTED!) */ function DOMIT_Notation() { DOMIT_DOMException::raiseException(DOMIT_NOT_SUPPORTED_ERR, 'Cannot instantiate DOMIT_Notation class. Notation nodes not yet supported.'); } //DOMIT_Notation } //DOMIT_Notation /** * Manages the generation of a DOMIT! document from SAX events * * @package domit-xmlparser * @subpackage domit-xmlparser-main * @author John Heinstein <johnkarl@nbnet.nb.ca> */ class DOMIT_Parser { /** @var Object A reference to the resulting xmldoc */ var $xmlDoc = null; /** @var Object A reference to the current node in the parsing process */ var $currentNode = null; /** @var Object A reference to the last child in the parsing process */ var $lastChild = null; /** @var boolean True if currently parsing a CDATA Section */ var $inCDATASection = false; //flag for Expat /** @var boolean True if currently parsing a Text node */ var $inTextNode = false; /** @var boolean True is CDATA Section nodes are not to be converted into Text nodes */ var $preserveCDATA; /** @var string A container for holding the currently parsed text data */ var $parseContainer = ''; /** @var string The current docutype text */ var $parseItem = ''; /** @var boolean True if waiting for an element to which to apply namespace declaration(s) */ var $waitingForElementToDeclareNamespaces = false; /** @var boolean True if waiting for an element to which to apply namespace declaration(s) */ var $tempNamespaceURIMap = array(); /** * Parses xml text using Expat * @param Object A reference to the DOM document that the xml is to be parsed into * @param string The text to be parsed * @param boolean True if CDATA Section nodes are not to be converted into Text nodes * @return boolean True if the parsing is successful */ function parse (&$myXMLDoc, $xmlText, $preserveCDATA = true) { $this->xmlDoc =& $myXMLDoc; $this->lastChild =& $this->xmlDoc; $this->preserveCDATA = $preserveCDATA; //create instance of expat parser (should be included in php distro) if (version_compare(phpversion(), '5.0', '<=')) { if ($this->xmlDoc->isNamespaceAware) { $parser = xml_parser_create_ns(''); } else { $parser = xml_parser_create(''); } } else { if ($this->xmlDoc->isNamespaceAware) { $parser = xml_parser_create_ns(); } else { $parser = xml_parser_create(); } } //set handlers for SAX events xml_set_object($parser, $this); xml_set_character_data_handler($parser, 'dataElement'); xml_set_default_handler($parser, 'defaultDataElement'); xml_set_notation_decl_handler($parser, 'notationElement'); xml_set_processing_instruction_handler($parser, 'processingInstructionElement'); xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); if (!$this->xmlDoc->preserveWhitespace) { xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); } else { xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0); } if ($this->xmlDoc->isNamespaceAware) { xml_set_start_namespace_decl_handler($parser, 'startNamespaceDeclaration'); xml_set_end_namespace_decl_handler($parser, 'endNamespaceDeclaration'); xml_set_element_handler($parser, 'startElementNS', 'endElement'); $this->xmlDoc->namespaceURIMap[DOMIT_XML_NAMESPACE] = 'xml'; } else { xml_set_element_handler($parser, 'startElement', 'endElement'); } //parse out whitespace - (XML_OPTION_SKIP_WHITE = 1 does not //seem to work consistently across versions of PHP and Expat if (!$this->xmlDoc->preserveWhitespace) { $xmlText = eregi_replace('>' . "[[:space:]]+" . '<' , '><', $xmlText); } $success = xml_parse($parser, $xmlText); $this->xmlDoc->errorCode = xml_get_error_code($parser); $this->xmlDoc->errorString = xml_error_string($this->xmlDoc->errorCode); xml_parser_free($parser); return $success; } //parse /** * Parses xml text using SAXY * @param Object A reference to the DOM document that the xml is to be parsed into * @param string The text to be parsed * @param boolean True if CDATA Section nodes are not to be converted into Text nodes * @return boolean True if the parsing is successful */ function parseSAXY(&$myXMLDoc, $xmlText, $preserveCDATA = true, $definedEntities) { require_once(DOMIT_INCLUDE_PATH . 'xml_saxy_parser.php'); $this->xmlDoc =& $myXMLDoc; $this->lastChild =& $this->xmlDoc; //create instance of SAXY parser $parser = new SAXY_Parser(); $parser->appendEntityTranslationTable($definedEntities); //not yet implemented in SAXY!!! $parser->preserveWhitespace = $this->xmlDoc->preserveWhitespace; if ($this->xmlDoc->isNamespaceAware) { $parser->setNamespaceAwareness(true); $parser->xml_set_start_namespace_decl_handler(array(&$this, 'startNamespaceDeclaration')); $parser->xml_set_end_namespace_decl_handler(array(&$this, 'endNamespaceDeclaration')); $parser->xml_set_element_handler(array(&$this, 'startElementNS'), array(&$this, 'endElement')); $this->xmlDoc->namespaceURIMap[DOMIT_XML_NAMESPACE] = 'xml'; } else { $parser->xml_set_element_handler(array(&$this, 'startElement'), array(&$this, 'endElement')); } $parser->xml_set_character_data_handler(array(&$this, 'dataElement')); $parser->xml_set_doctype_handler(array(&$this, 'doctypeElement')); $parser->xml_set_comment_handler(array(&$this, 'commentElement')); $parser->xml_set_processing_instruction_handler(array(&$this, 'processingInstructionElement')); if ($preserveCDATA) { $parser->xml_set_cdata_section_handler(array(&$this, 'cdataElement')); } $success = $parser->parse($xmlText); $this->xmlDoc->errorCode = $parser->xml_get_error_code(); $this->xmlDoc->errorString = $parser->xml_error_string($this->xmlDoc->errorCode); return $success; } //parseSAXY /** * Generates and appends a new text node from the parseContainer text */ function dumpTextNode() { $currentNode =& $this->xmlDoc->createTextNode($this->parseContainer); $this->lastChild->appendChild($currentNode); $this->inTextNode = false; $this->parseContainer = ''; } //dumpTextNode /** * Catches a start element event and processes the data * @param Object A reference to the current SAX parser * @param string The tag name of the current element * @param Array An array of the element attributes */ function startElement(&$parser, $name, $attrs) { if ($this->inTextNode) { $this->dumpTextNode(); } $currentNode =& $this->xmlDoc->createElement($name); $this->lastChild->appendChild($currentNode); reset ($attrs); while (list($key, $value) = each ($attrs)) { $currentNode->setAttribute($key, $value); } $this->lastChild =& $currentNode; } //startElement /** * Catches a start element event and processes the data * @param Object A reference to the current SAX parser * @param string The tag name of the current element * @param Array An array of the element attributes */ function startElementNS(&$parser, $name, $attrs) { if ($this->inTextNode) { $this->dumpTextNode(); } $colonIndex = strrpos($name, ":"); if ($colonIndex !== false) { //force to lower case because Expat for some reason forces to upper case $namespaceURI = strtolower(substr($name, 0, $colonIndex)); $prefix = $this->xmlDoc->namespaceURIMap[$namespaceURI]; if ($prefix != '') { $qualifiedName = $prefix . ":" . substr($name, ($colonIndex + 1)); } else { $qualifiedName = substr($name, ($colonIndex + 1)); } } else { $namespaceURI = ''; $qualifiedName = $name; } $currentNode =& $this->xmlDoc->createElementNS($namespaceURI, $qualifiedName); $this->lastChild->appendChild($currentNode); //add attributes reset ($attrs); while (list($key, $value) = each ($attrs)) { $colonIndex = strrpos($key, ":"); if ($colonIndex !== false) { //force to lower case because Expat for some reason forces to upper case $namespaceURI = strtolower(substr($key, 0, $colonIndex)); $qualifiedName = $this->xmlDoc->namespaceURIMap[$namespaceURI] . ":" . substr($key, ($colonIndex + 1));; } else { //if containing element has a namespace, technically //attribute namespace should be added here, but we'll do it elsewhere //so toNormalizedString outputs the same things as is input $namespaceURI = ''; $qualifiedName = $key; } $currentNode->setAttributeNS($namespaceURI, $qualifiedName, $value); } //and add xmlns attributes if ($this->waitingForElementToDeclareNamespaces) { //map namespace declarations to element foreach ($this->tempNamespaceURIMap as $key => $value) { $currentNode->namespaceURIMap[$key] = $value ; //xmlns prefix has prefix: http://www.w3.org/2000/xmlns/ $currentNode->setAttributeNS(DOMIT_XMLNS_NAMESPACE, ('xmlns:' . $value), $key); } //reset variables $this->tempNamespaceURIMap = array(); $this->waitingForElementToDeclareNamespaces = false; } $this->lastChild =& $currentNode; } //startElementNS /** * Catches an end element event and processes the data * @param Object A reference to the current SAX parser * @param string The tag name of the current element */ function endElement(&$parser, $name) { if ($this->inTextNode) { $this->dumpTextNode(); } $this->lastChild =& $this->lastChild->parentNode; } //endElement /** * Catches a data event and processes the text * @param Object A reference to the current SAX parser * @param string The current text data */ function dataElement(&$parser, $data) { if (!$this->inCDATASection) { $this->inTextNode = true; } $this->parseContainer .= $data; } //dataElement /** * Catches a CDATA Section event and processes the text * @param Object A reference to the current SAX parser * @param string The current text data */ function cdataElement(&$parser, $data) { $currentNode =& $this->xmlDoc->createCDATASection($data); $this->lastChild->appendChild($currentNode); } //cdataElement /** * Catches a default data event and processes the data * @param Object A reference to the current SAX parser * @param string The current data */ function defaultDataElement(&$parser, $data) { if ((strlen($data) > 2) && ($this->parseItem == '')){ $pre = strtoupper(substr($data, 0, 3)); switch ($pre) { case '<?X': //xml declaration $this->processingInstructionElement($parser, 'xml', substr($data, 6, (strlen($data) - 6 - 2))); break; case '<!E': //dtd entity $this->xmlDoc->doctype .= "\n " . $data; break; case '<![': //cdata section coming if ($this->preserveCDATA) { $this->inCDATASection = true; } break; case '<!-': //comment $currentNode =& $this->commentElement($this, substr($data, 4, (strlen($data) - 7))); break; case '<!D': //doctype $this->parseItem = 'doctype'; $this->parseContainer = $data; break; case ']]>': //cdata end tag if ($this->preserveCDATA) { $currentNode =& $this->xmlDoc->createCDATASection($this->parseContainer); $this->lastChild->appendChild($currentNode); $this->inCDATASection = false; $this->parseContainer = ''; } else { $this->dumpTextNode(); } break; } } else { switch ($this->parseItem) { case 'doctype': $this->parseContainer .= $data; if ($data == '>') { $this->doctypeElement($parser, $this->parseContainer); $this->parseContainer = ''; $this->parseItem = ''; } else if ($data == '[') { $this->parseItem = 'doctype_inline'; } break; case 'doctype_inline': $this->parseContainer .= $data; if ($data == ']') { $this->parseItem = 'doctype'; } else if ($data{(strlen($data) - 1)} == '>') { $this->parseContainer .= "\n "; } break; } } } //defaultDataElement /** * Catches a doctype event and processes the data * @param Object A reference to the current SAX parser * @param string The current data */ function doctypeElement(&$parser, $data) { $start = strpos($data, '<!DOCTYPE'); $name = trim(substr($data, $start)); $end = strpos($name, ' '); $name = substr($name, 0, $end); $currentNode = new DOMIT_DocumentType($name, $data); $currentNode->ownerDocument =& $this->xmlDoc; $this->lastChild->appendChild($currentNode); $this->xmlDoc->doctype =& $currentNode; } //doctypeElement /** * Catches a notation node event and processes the data * @param Object A reference to the current SAX parser * @param string The current notation data */ function notationElement(&$parser, $data) { //add to doctype string if (($this->parseItem == 'doctype_inline') || ($this->parseItem == 'doctype')) { $this->parseContainer .= $data; } } //notationElement /** * Catches a comment node event and processes the data * @param Object A reference to the current SAX parser * @param string The comment data */ function commentElement(&$parser, $data) { if ($this->inTextNode) { $this->dumpTextNode(); } $currentNode =& $this->xmlDoc->createComment($data); $this->lastChild->appendChild($currentNode); } //commentElement /** * Catches a processing instruction node event and processes the data * @param Object A reference to the current SAX parser * @param string The target of the processing instruction data * @param string The processing instruction data */ function processingInstructionElement(&$parser, $target, $data) { if ($this->inTextNode) { $this->dumpTextNode(); } $currentNode =& $this->xmlDoc->createProcessingInstruction($target, $data); $this->lastChild->appendChild($currentNode); if (strtolower($target) == 'xml') { $this->xmlDoc->xmlDeclaration =& $currentNode; } } //processingInstructionElement /** * Catches a start namespace declaration event and processes the data * @param Object A reference to the current SAX parser * @param string The namespace prefix * @param string The namespace uri */ function startNamespaceDeclaration(&$parser, $prefix, $uri) { //make uri lower case because Expat forces it to upper case for some reason $this->xmlDoc->namespaceURIMap[strtolower($uri)] = $prefix; //set up a switch so when the target element arrives, namespaces can be mapped to it $this->waitingForElementToDeclareNamespaces = true; $this->tempNamespaceURIMap[strtolower($uri)] = $prefix; } //startNamespaceDeclaration /** * Catches an end namespace declaration event * @param Object A reference to the current SAX parser * @param string The namespace prefix */ function endNamespaceDeclaration(&$parser, $prefix) { //do nothing; could remove from map, but would hardly be optimal } //endNamespaceDeclaration } //DOMIT_Parser ?>