home *** CD-ROM | disk | FTP | other *** search
- <?php
- // {{{ license
-
- // +----------------------------------------------------------------------+
- // | PHP version 4.0 |
- // +----------------------------------------------------------------------+
- // | Copyright (c) 1997-2001 The PHP Group |
- // +----------------------------------------------------------------------+
- // | This source file is subject to version 2.0 of the PHP license, |
- // | that is bundled with this package in the file LICENSE, and is |
- // | available at through the world-wide-web at |
- // | http://www.php.net/license/2_02.txt. |
- // | If you did not receive a copy of the PHP license and are unable to |
- // | obtain it through the world-wide-web, please send a note to |
- // | license@php.net so we can mail you a copy immediately. |
- // +----------------------------------------------------------------------+
- // | Authors: Dan Allen <dan@mojavelinux.com> |
- // +----------------------------------------------------------------------+
-
- // $Id: common.php,v 1.23 2007/08/04 20:24:41 cweiske Exp $
-
- // }}}
- // {{{ description
-
- // Core DOM and internal pointer methods for the Xpath/DOM XML manipulation and query interface.
-
- // }}}
- // {{{ functions
-
- /**
- * is_a is only defined in php for user functions,
- * so I implemented its functionality for php objects
- * until they fix (or never fix) this problem
- *
- * @param object $class the class to check
- * @param string $match class name you are looking for
- *
- * @access public
- * @return boolean whether the class is of the class type or a descendent of the class
- */
- function is_a_php_class($class, $match)
- {
- if (empty($class)) {
- return false;
- }
-
- $class = is_object($class) ? get_class($class) : $class;
- if (strtolower($class) == strtolower($match)) {
- return true;
- }
-
- return is_a_php_class(get_parent_class($class), $match);
- }
-
- // }}}
-
- // {{{ class XML_XPath_common
-
- /**
- * The XML_XPath_common class contains the DOM functions used to manipulate
- * and maneuver through the xml tree. The main thing to understand is
- * that all operations work around a single pointer. This pointer is your
- * place holder within the document. Each function you run assumes the
- * node in reference is your pointer. However, every function can take
- * an xpath query or DOM object reference, so that the pointer can be set
- * before working on the node, and can retain this position if specified.
- * Every DOM function call has a init() and shutdown() call. This function
- * prepares the pointer to the requested location in the tree if an xpath query
- * or pointer object is provided. In addition, the init() function checks to
- * see that the node type is acceptable for the method, and if not throws an
- * XML_XPath_Error exception. If you want to execute a function and then remain
- * in the location of your query, then you specify that you want to move the pointer.
- * For the DOM step functions, this is the default action.
- *
- * Note: All offsets in the CharacterData interface start from 0.
- *
- * The object model of XML_XPath is as follows (indentation means inheritance):
- *
- * XML_XPath_common The main functionality of the XML_XPath class is here. This
- * | holds all the DOM functions for manipulating and maneuvering
- * | through the DOM tree.
- * |
- * +-XML_XPath The frontend for the XML_XPath implementation. Provides default
- * | functions for preparing the main document, running xpath queries
- * | and handling errorMessages.
- * |
- * +-Result Extended from the XML_XPath_common class, this object is returned when
- * an xpath query is executed and can be used to cycle through the
- * result nodeset or data
- *
- * @version Revision: 1.1
- * @author Dan Allen <dan@mojavelinux.com>
- * @access public
- * @since PHP 4.2.1
- * @package XML_XPath
- */
-
- // }}}
- class XML_XPath_common {
- // {{{ properties
-
- /**
- * domxml node of the current location in the xml document
- * @var object $pointer
- */
- var $pointer;
-
- /**
- * domxml node bookmark used for holding a place in the xml document
- * @var object $bookmark
- */
- var $bookmark;
-
- /**
- * when working with the xml document, ignore the presence of blank nodes (white space)
- * @var boolean $skipBlanks
- */
- var $skipBlanks = true;
-
- /**
- * path to xmllint used for reformating the xml output
- * [!] should be using System_Command for this [!]
- * @var string $xmllint
- */
- var $xmllint = 'xmllint';
-
- // }}}
- // {{{ string nodeName()
-
- /**
- * Return the name of this node, depending on its type, according to the DOM recommendation
- *
- * @param string $in_xpathQuery (optional) quick xpath query
- * @param boolean $in_movePointer (optional) move internal pointer with quick xpath query
- *
- * @access public
- * @return string name of node corresponding to DOM recommendation {or XML_XPath_Error exception}
- */
- function nodeName($in_xpathQuery = null, $in_movePointer = false)
- {
- if (!$this->pointer) {
- return PEAR::raiseError(null, XML_XPATH_NULL_POINTER, null, E_USER_WARNING, '', 'XML_XPath_Error', true);
- }
-
- if ($hasQuery = !is_null($in_xpathQuery) && XML_XPath::isError($result = $this->_quick_evaluate_init($in_xpathQuery, $in_movePointer))) {
- return $result;
- }
-
- $nodeName = $this->pointer->node_name();
-
- if ($hasQuery && !$in_movePointer) {
- $this->_restore_bookmark();
- }
-
- return $nodeName;
- }
-
- // }}}
- // {{{ int nodeType()
-
- /**
- * Returns the integer value constant corresponding to the DOM node type
- *
- * @param string $in_xpathQuery (optional) quick xpath query
- * @param boolean $in_movePointer (optional) move internal pointer with quick xpath query
- *
- * @access public
- * @return int DOM type of the node {or XML_XPath_Error exception}
- */
- function nodeType($in_xpathQuery = null, $in_movePointer = false)
- {
- if (!$this->pointer) {
- return PEAR::raiseError(null, XML_XPATH_NULL_POINTER, null, E_USER_WARNING, '', 'XML_XPath_Error', true);
- }
-
- if ($hasQuery = !is_null($in_xpathQuery) && XML_XPath::isError($result = $this->_quick_evaluate_init($in_xpathQuery, $in_movePointer))) {
- return $result;
- }
-
- $nodeType = $this->pointer->node_type();
-
- if ($hasQuery && !$in_movePointer) {
- $this->_restore_bookmark();
- }
-
- return $nodeType;
- }
-
- // }}}
- // {{{ object childNodes()
-
- /**
- * Retrieves the child nodes from the element node as an XML_XPath_result object
- *
- * Similar to an xpath query, this function will grab all the first descendant child
- * nodes of the element node at the current position and will create an XML_XPath_result
- * object of type nodeset with each of the child nodes as the nodes.
- * DOM query functions do not take an xpathQuery argument
- *
- * @access public
- * @return object XML_XPath_result object of type nodeset
- * [!] important note: since we had to hack the result object a bit, you cannot sort the
- * result object when generated in this manner right now [!]
- */
- function &childNodes()
- {
- if (!$this->pointer) {
- return PEAR::raiseError(null, XML_XPATH_NULL_POINTER, null, E_USER_WARNING, '', 'XML_XPath_Error', true);
- }
-
- $nodeset = array();
- foreach($this->pointer->child_nodes() as $childNode) {
- // if this is a blank node and we are skipping blank nodes...skip to next child
- if ($childNode->is_blank_node() && $this->skipBlanks) {
- continue;
- }
- $nodeset[] = $childNode;
- }
- return new XML_XPath_result($nodeset, XPATH_NODESET, array($this->pointer, '/*'), $this->ctx, $this->xml);
- }
-
- // }}}
- // {{{ object getElementsByTagName()
-
- /**
- * Create an XML_XPath_result object with the elements with the specified tagname
- *
- * DOM query functions do not take an xpathQuery argument
- *
- * @param string $in_tagName
- *
- * @return object XML_XPath_result object of matching nodes
- * @access public
- */
- function getElementsByTagName($in_tagName)
- {
- // since we can't do an actual xpath query, we need to create a pseudo xpath result
- $nodeset = $this->xml->get_elements_by_tagname($in_tagName);
- return new XML_XPath_result($nodeset, XPATH_NODESET, array(null, '//' . $in_tagName), $this->ctx, $this->xml);
- }
-
- // }}}
- // {{{ boolean documentElement()
-
- /**
- * Move to the document element
- *
- * @param boolean $in_movePointer (optional) move the internal pointer or return reference
- *
- * @access public
- * @return boolean whether pointer was moved or object pointer to document element
- */
- function documentElement($in_movePointer = true)
- {
- if (!$this->pointer) {
- return PEAR::raiseError(null, XML_XPATH_NULL_POINTER, null, E_USER_WARNING, '', 'XML_XPath_Error', true);
- }
-
- $documentElement = $this->xml->document_element();
- if ($in_movePointer) {
- $this->pointer = $documentElement;
- return true;
- }
- else {
- return $documentElement;
- }
- }
-
- // }}}
- // {{{ boolean parentNode()
-
- /**
- * Moves the internal pointer to the parent of the current node or returns the pointer.
- * Step functions do not take an xpathQuery argument
- *
- * @param boolean $in_movePointer (optional) move the internal pointer or return reference
- *
- * @access public
- * @return boolean whether pointer was moved or object pointer to parent
- */
- function parentNode($in_movePointer = true)
- {
- if (!$this->pointer) {
- return PEAR::raiseError(null, XML_XPATH_NULL_POINTER, null, E_USER_WARNING, '', 'XML_XPath_Error', true);
- }
-
- $parent = $this->pointer->parent_node();
- if ($parent) {
- if ($in_movePointer) {
- $this->pointer = $parent;
- return true;
- }
- else {
- return $parent;
- }
- }
- else {
- return false;
- }
- }
-
- // }}}
- // {{{ boolean nextSibling()
-
- /**
- * Moves the internal pointer to the next sibling of the current node, or returns the pointer.
- * If the flag is on to skip blank nodes then the first non-blank node is used.
- * Step functions do not take an xpathQuery argument
- *
- * @param boolean $in_movePointer (optional) move the internal pointer or return reference
- *
- * @access public
- * @return boolean whether the pointer was moved or object pointer to next sibling
- */
- function nextSibling($in_movePointer = true)
- {
- if (!$this->pointer) {
- return PEAR::raiseError(null, XML_XPATH_NULL_POINTER, null, E_USER_WARNING, '', 'XML_XPath_Error', true);
- }
-
- if (!$this->pointer->next_sibling()) {
- return false;
- }
-
- $next = $this->pointer->next_sibling();
- if ($this->skipBlanks) {
- while (true) {
- // make sure we are not already at the end
- if (!$next) {
- $next = false;
- break;
- }
- // we have found a non-blank node
- elseif (!$next->is_blank_node()) {
- break;
- }
- // we found a blank node at the very end
- elseif (!$next = $next->next_sibling()) {
- $next = false;
- break;
- }
- }
- }
- if ($next) {
- if ($in_movePointer) {
- $this->pointer = $next;
- return true;
- }
- else {
- return $next;
- }
- }
- else {
- return false;
- }
- }
-
- // }}}
- // {{{ boolean previousSibling()
-
- /**
- * Moves the internal pointer to the previous sibling
- * of the current node or returns the pointer.
- * If the flag is on to skip blank nodes then the first non-blank node is used.
- * Step functions do not take an xpathQuery argument
- *
- * @param boolean $in_movePointer (optional) move the internal pointer or return reference
- *
- * @access public
- * @return boolean whether the pointer was moved or object pointer to previous sibling
- */
- function previousSibling($in_movePointer = true)
- {
- if (!$this->pointer) {
- return PEAR::raiseError(null, XML_XPATH_NULL_POINTER, null, E_USER_WARNING, '', 'XML_XPath_Error', true);
- }
-
- if (!$this->pointer->previous_sibling()) {
- return false;
- }
-
- $previous = $this->pointer->previous_sibling();
- if ($this->skipBlanks) {
- while (true) {
- // we have found a non-blank node
- if (!$previous->is_blank_node()) {
- break;
- }
- // we have arrived at the beginning
- elseif (!$previous = $previous->previous_sibling()) {
- $previous = false;
- break;
- }
- }
- }
- if ($previous) {
- if ($in_movePointer) {
- $this->pointer = $previous;
- return true;
- }
- else {
- return $previous;
- }
- }
- else {
- return false;
- }
- }
-
- // }}}
- // {{{ boolean firstChild()
-
- /**
- * Moves the pointer to the first child of this node or returns the first node.
- * If the flag is on to skip blank nodes then the first non-blank node is used.
- * Step functions do not take an xpathQuery argument
- *
- * @param boolean $in_movePointer (optional) move the internal pointer or return reference
- *
- * @access public
- * @return boolean whether the pointer was moved to the first child or returns the first child
- */
- function firstChild($in_movePointer = true)
- {
- if (!$this->pointer) {
- return PEAR::raiseError(null, XML_XPATH_NULL_POINTER, null, E_USER_WARNING, '', 'XML_XPath_Error', true);
- }
-
- if (!$this->pointer->has_child_nodes()) {
- return false;
- }
-
- $first = $this->pointer->first_child();
- if ($this->skipBlanks) {
- while (true) {
- // we have found a non-blank node
- if (!$first->is_blank_node()) {
- break;
- }
- // we have arrived at the end
- elseif (!$first = $first->next_sibling()) {
- $first = false;
- break;
- }
- }
- }
- if ($first) {
- if ($in_movePointer) {
- $this->pointer = $first;
- return true;
- }
- else {
- return $first;
- }
- }
- else {
- return false;
- }
- }
-
- // }}}
- // {{{ boolean lastChild()
-
- /**
- * Moves the pointer to the last child of this node or returns the last child.
- * If the flag is on to skip blank nodes then the first non-blank node is used.
- * Step functions do not take an xpathQuery argument
- *
- * @param boolean $in_movePointer (optional) move the internal pointer or return reference
- *
- * @access public
- * @return boolean whether the pointer was moved to the last child or returns the last child
- */
- function lastChild($in_movePointer = true)
- {
- if (!$this->pointer) {
- return PEAR::raiseError(null, XML_XPATH_NULL_POINTER, null, E_USER_WARNING, '', 'XML_XPath_Error', true);
- }
-
- if (!$this->pointer->has_child_nodes()) {
- return false;
- }
-
- $last = $this->pointer->last_child();
- if ($this->skipBlanks) {
- while (true) {
- // we have found a non-blank node
- if (!$last->is_blank_node()) {
- break;
- }
- // we have arrived at the beginning
- elseif (!$last = $last->previous_sibling()) {
- $last = false;
- break;
- }
- }
- }
- if ($last) {
- if ($in_movePointer) {
- $this->pointer = $last;
- return true;
- }
- else {
- return $last;
- }
- }
- else {
- return false;
- }
- }
-
- // }}}
- // {{{ boolean hasChildNodes()
-
- /**
- * Returns whether this node has any children.
- *
- * @param string $in_xpathQuery (optional) quick xpath query
- * @param boolean $in_movePointer (optional) move internal pointer
- *
- * @access public
- * @return boolean has child nodes {or XML_XPath_Error exception}
- */
- function hasChildNodes($in_xpathQuery = null, $in_movePointer = false)
- {
- if (!$this->pointer) {
- return PEAR::raiseError(null, XML_XPATH_NULL_POINTER, null, E_USER_WARNING, '', 'XML_XPath_Error', true);
- }
-
- if ($hasQuery = !is_null($in_xpathQuery) && XML_XPath::isError($result = $this->_quick_evaluate_init($in_xpathQuery, $in_movePointer))) {
- return $result;
- }
-
- $hasChildNodes = $this->pointer->has_child_nodes();
-
- if ($hasQuery && !$in_movePointer) {
- $this->_restore_bookmark();
- }
-
- return $hasChildNodes;
- }
-
- // }}}
- // {{{ boolean hasAttributes()
-
- /**
- * Returns whether this node has any attributes.
- *
- * @param string $in_xpathQuery (optional) quick xpath query
- * @param boolean $in_movePointer (optional) move internal pointer
- *
- * @access public
- * @return boolean attributes exist {or XML_XPath_Error exception}
- */
- function hasAttributes($in_xpathQuery = null, $in_movePointer = false)
- {
- if (!$this->pointer) {
- return PEAR::raiseError(null, XML_XPATH_NULL_POINTER, null, E_USER_WARNING, '', 'XML_XPath_Error', true);
- }
-
- if ($hasQuery = !is_null($in_xpathQuery) && XML_XPath::isError($result = $this->_quick_evaluate_init($in_xpathQuery, $in_movePointer))) {
- return $result;
- }
-
- $hasAttributes = $this->pointer->has_attributes();
-
- if ($hasQuery && !$in_movePointer) {
- $this->_restore_bookmark();
- }
-
- return $hasAttributes;
- }
-
- // }}}
- // {{{ boolean hasAttribute()
-
- /**
- * Returns true when an attribute with a given name is specified on this element
- * false otherwise.
- *
- * @param string $in_name name of attribute
- * @param string $in_xpathQuery (optional) quick xpath query
- * @param boolean $in_movePointer (optional) move internal pointer
- *
- * @access public
- * @return boolean existence of attribute {or XML_XPath_Error exception}
- */
- function hasAttribute($in_name, $in_xpathQuery = null, $in_movePointer = false)
- {
- if (!$this->pointer) {
- return PEAR::raiseError(null, XML_XPATH_NULL_POINTER, null, E_USER_WARNING, '', 'XML_XPath_Error', true);
- }
-
- if (XML_XPath::isError($result = $this->_quick_evaluate_init($in_xpathQuery, $in_movePointer, array(XML_ELEMENT_NODE)))) {
- return $result;
- }
-
- $hasAttribute = $this->pointer->has_attribute($in_name) ? true : false;
-
- if (!is_null($in_xpathQuery) && !$in_movePointer) {
- $this->_restore_bookmark();
- }
-
- return $hasAttribute;
- }
-
- // }}}
- // {{{ array getAttributes()
-
- /**
- * Return an associative array of attribute names as the keys and attribute values as the
- * values. This is not a DOM function, but is a convenient addition.
- *
- * @param string $in_xpathQuery (optional) quick xpath query
- * @param boolean $in_movePointer (optional) move internal pointer
- *
- * @access public
- * @return array associative array of attributes {or XML_XPath_Error exception}
- */
- function getAttributes($in_xpathQuery = null, $in_movePointer = false)
- {
- if (!$this->pointer) {
- return PEAR::raiseError(null, XML_XPATH_NULL_POINTER, null, E_USER_WARNING, '', 'XML_XPath_Error', true);
- }
-
- if ($hasQuery = !is_null($in_xpathQuery) && XML_XPath::isError($result = $this->_quick_evaluate_init($in_xpathQuery, $in_movePointer))) {
- return $result;
- }
-
- $return = array();
- if (is_array($attributeNodes = $this->pointer->attributes())) {
- foreach($attributeNodes as $attributeNode) {
- $return[$attributeNode->name] = $attributeNode->value;
- }
- }
-
- if ($hasQuery && !$in_movePointer) {
- $this->_restore_bookmark();
- }
-
- return $return;
- }
-
- // }}}
- // {{{ string getAttribute()
-
- /**
- * Retrieves an attribute value by name from the element node at the current pointer.
- *
- * Grab the attribute value if it exists and return it. If the attribute does not
- * exist, this function will return the boolean 'false', so be sure to check properly
- * if the value is "" or if the attribute doesn't exist at all. This function is the
- * only attribute function which allows you to step onto the attribute node.
- *
- * @param string $in_name Name of the attribute
- * @param string $in_xpathQuery (optional) quick xpath query
- * @param boolean $in_movePointer (optional) move the internal pointer with quick xpath query
- *
- * @access public
- * @return string value of attribute or false if attribute DNE {or XML_XPath_Error exception}
- */
- function getAttribute($in_name, $in_xpathQuery = null, $in_movePointer = false)
- {
- if (!$this->pointer) {
- return PEAR::raiseError(null, XML_XPATH_NULL_POINTER, null, E_USER_WARNING, '', 'XML_XPath_Error', true);
- }
-
- if (XML_XPath::isError($result = $this->_quick_evaluate_init($in_xpathQuery, $in_movePointer, array(XML_ELEMENT_NODE)))) {
- return $result;
- }
-
- $result = $this->pointer->get_attribute($in_name);
- // if we found the attribute, move to it if we are moving the pointer
- if ($result && $in_movePointer) {
- $this->pointer = $this->pointer->get_attribute_node($in_name);
- }
-
- if (!is_null($in_xpathQuery) && !$in_movePointer) {
- $this->_restore_bookmark();
- }
-
- return $result;
- }
-
- // }}}
- // {{{ boolean setAttribute()
-
- /**
- * Adds a new attribute. If an attribute with that name is already present
- * in the element, its value is changed to be that of the value parameter.
- * Invalid characters are escaped.
- *
- * @param string $in_name name of the attribute to be set
- * @param string $in_value new attribute value
- * @param string $in_xpathQuery (optional) quick xpath query
- * @param boolean $in_movePointer (optional) move internal pointer
- *
- * @access public
- * @return boolean success {or XML_XPath_Error exception}
- */
- function setAttribute($in_name, $in_value, $in_xpathQuery = null, $in_movePointer = false)
- {
- if (!$this->pointer) {
- return PEAR::raiseError(null, XML_XPATH_NULL_POINTER, null, E_USER_WARNING, '', 'XML_XPath_Error', true);
- }
-
- if (XML_XPath::isError($result = $this->_quick_evaluate_init($in_xpathQuery, $in_movePointer, array(XML_ELEMENT_NODE)))) {
- return $result;
- }
-
- $result = $this->pointer->set_attribute($in_name, $in_value);
-
- if (!is_null($in_xpathQuery) && !$in_movePointer) {
- $this->_restore_bookmark();
- }
-
- return $result;
- }
-
- // }}}
- // {{{ void removeAttribute()
-
- /**
- * Remove the attribute by name.
- *
- * @param string $in_name name of the attribute
- * @param string $in_xpathQuery (optional) quick xpath query
- * @param boolean $in_movePointer (optional) move internal pointer
- *
- * @access public
- * @return boolean success {or XML_XPath_Error exception}
- */
- function removeAttribute($in_name, $in_xpathQuery = null, $in_movePointer = false)
- {
- if (!$this->pointer) {
- return PEAR::raiseError(null, XML_XPATH_NULL_POINTER, null, E_USER_WARNING, '', 'XML_XPath_Error', true);
- }
-
- if (XML_XPath::isError($result = $this->_quick_evaluate_init($in_xpathQuery, $in_movePointer, array(XML_ELEMENT_NODE)))) {
- return $result;
- }
-
- $result = $this->pointer->remove_attribute($in_name);
-
- if (!is_null($in_xpathQuery) && !$in_movePointer) {
- $this->_restore_bookmark();
- }
-
- return $result;
- }
-
- // }}}
- // {{{ string substringData()
-
- /**
- * Extracts a range of data from the node. Takes an offset and a count, which are optional
- * and will default to retrieving the whole string. If an XML_ELEMENT_NODE provided, then
- * it first concats all the adjacent text nodes recusively and works on those.
- * ??? implement wholeText() which concats all text nodes adjacent to a text node ???
- *
- * @param int $in_offset offset of substring to extract
- * @param int $in_count length of substring to extract
- * @param string $in_xpathQuery (optional) quick xpath query
- * @param boolean $in_movePointer (optional) move internal pointer
- *
- * @access public
- * @return string substring of the character data {or XML_XPath_Error exception}
- */
- function substringData($in_offset = 0, $in_count = 0, $in_xpathQuery = null, $in_movePointer = false)
- {
- if (!$this->pointer) {
- return PEAR::raiseError(null, XML_XPATH_NULL_POINTER, null, E_USER_WARNING, '', 'XML_XPath_Error', true);
- }
-
- if (XML_XPath::isError($result = $this->_quick_evaluate_init($in_xpathQuery, $in_movePointer, array(XML_TEXT_NODE, XML_ELEMENT_NODE, XML_CDATA_SECTION_NODE, XML_COMMENT_NODE)))) {
- return $result;
- }
-
- if (!is_int($in_count) || $in_count < 0) {
- $return = PEAR::raiseError(null, XML_XPATH_INDEX_SIZE, null, E_USER_WARNING, "Count: $in_offset", 'XML_XPath_Error', true);
- }
- elseif (!is_int($in_offset) || $in_offset < 0 || $in_offset > strlen($content = $this->pointer->get_content())) {
- $return = PEAR::raiseError(null, XML_XPATH_INDEX_SIZE, null, E_USER_WARNING, "Offset: $in_offset", 'XML_XPath_Error', true);
- }
- else {
- $return = $in_count ? substr($content, $in_offset, $in_count) :
- substr($content, $in_offset);
- }
-
- if (!is_null($in_xpathQuery) && !$in_movePointer) {
- $this->_restore_bookmark();
- }
-
- return $return;
- }
-
- // }}}
- // {{{ void insertData()
-
- /**
- * Will insert data at offset for a text node.
- *
- * @param string $in_content content to be inserted
- * @param int $in_offset offset to insert data
- * @param string $in_xpathQuery (optional) quick xpath query
- * @param boolean $in_movePointer (optional) move internal pointer
- *
- * @access public
- * @return void {or XML_XPath_Error exception}
- */
- function insertData($in_content, $in_offset = 0, $in_xpathQuery = null, $in_movePointer = false)
- {
- return $this->_set_content($in_content, $in_xpathQuery, $in_movePointer, false, $in_offset);
- }
-
- // }}}
- // {{{ void deleteData()
-
- /**
- * Will delete data at offset and for count for a text node.
- *
- * @param int $in_offset (optional) offset to delete data
- * @param int $in_count (optional) number of characters to delete
- * @param string $in_xpathQuery (optional) quick xpath query
- * @param boolean $in_movePointer (optional) move internal pointer
- *
- * @access public
- * @return void {or XML_XPath_Error exception}
- */
- function deleteData($in_offset = 0, $in_count = 0, $in_xpathQuery = null, $in_movePointer = false)
- {
- return $this->_set_content(null, $in_xpathQuery, $in_movePointer, true, $in_offset, $in_count);
- }
-
- // }}}
- // {{{ void replaceData()
-
- /**
- * Will replace data at offset and for count with content
- *
- * @param string $in_content content to insert
- * @param int $in_offset (optional) offset to replace data
- * @param int $in_count (optional) number of characters to replace
- * @param string $in_xpathQuery (optional) quick xpath query
- * @param boolean $in_movePointer (optional) move internal pointer
- *
- * @access public
- * @return void {or XML_XPath_Error exception}
- */
- function replaceData($in_content, $in_offset = 0, $in_count = 0, $in_xpathQuery = null, $in_movePointer = false)
- {
- return $this->_set_content($in_content, $in_xpathQuery, $in_movePointer, true, $in_offset, $in_count);
- }
-
- // }}}
- // {{{ void appendData()
-
- /**
- * Will append data to end of text node.
- *
- * @param string $in_content content to append
- * @param string $in_xpathQuery (optional) quick xpath query
- * @param boolean $in_movePointer (optional) move internal pointer
- *
- * @access public
- * @return void {or XML_XPath_Error exception}
- */
- function appendData($in_content, $in_xpathQuery = null, $in_movePointer = false)
- {
- return $this->_set_content($in_content, $in_xpathQuery, $in_movePointer, false, null);
- }
-
- // }}}
- // {{{ object replaceChild()
-
- /**
- * Replaces the old child with the new child. If the new child is already in the document,
- * it is first removed (not implemented yet). If the new child is a document fragment, then
- * all of the nodes are inserted in the location of the old child.
- *
- * @param mixed $in_xmlData document fragment or node
- * @param string $in_xpathQuery (optional) quick xpath query
- * @param boolean $in_movePointer (optional) move internal pointer
- *
- * @access public
- * @return object pointer to old node {or XML_XPath_Error exception}
- */
- function replaceChild($in_xmlData, $in_xpathQuery = null, $in_movePointer = false)
- {
- if (!$this->pointer) {
- return PEAR::raiseError(null, XML_XPATH_NULL_POINTER, null, E_USER_WARNING, '', 'XML_XPath_Error', true);
- }
-
- if (XML_XPath::isError($result = $this->_quick_evaluate_init($in_xpathQuery, $in_movePointer, array(XML_ELEMENT_NODE, XML_TEXT_NODE, XML_COMMENT_NODE, XML_CDATA_SECTION_NODE, XML_PI_NODE)))) {
- return $result;
- }
-
- if (XML_XPath::isError($importedNodes = $this->_build_fragment($in_xmlData))) {
- if (!is_null($in_xpathQuery) && !$in_movePointer) {
- $this->_restore_bookmark();
- }
-
- return $importedNodes;
- }
-
- $parent = $this->pointer->parent_node();
- $lastNodeIndex = sizeOf($importedNodes) - 1;
- // run through all the new nodes...on the last new node, run replace_child()
- foreach($importedNodes as $index => $importedNode) {
- if ($index == $lastNodeIndex) {
- $oldNode = $parent->replace_child($importedNode, $this->pointer);
- }
- else {
- $parent->insert_before($importedNode, $this->pointer);
- }
- }
-
- if (!is_null($in_xpathQuery) && !$in_movePointer) {
- $this->_restore_bookmark();
- }
-
- return new XML_XPath_result(array($oldNode), XPATH_NODESET, null, $this->ctx, $this->xml);
- }
-
- // }}}
- // {{{ object appendChild()
-
- /**
- * Adds the node or document fragment to the end of the list of children. If the node
- * is already in the tree it is first removed (not sure if this works yet)
- *
- * @param mixed $in_xmlData string document fragment or node
- * @param string $in_xpathQuery (optional) quick xpath query
- * @param boolean $in_movePointer move internal pointer
- *
- * @access public
- * @return object pointer to the first of the nodes appended {or XML_XPath_Error exception}
- */
- function appendChild($in_xmlData, $in_xpathQuery = null, $in_movePointer = false)
- {
- if (!$this->pointer) {
- return PEAR::raiseError(null, XML_XPATH_NULL_POINTER, null, E_USER_WARNING, '', 'XML_XPath_Error', true);
- }
-
- if (XML_XPath::isError($result = $this->_quick_evaluate_init($in_xpathQuery, $in_movePointer, array(XML_ELEMENT_NODE, XML_DOCUMENT_NODE)))) {
- return $result;
- }
-
- // if this is a document node, make sure no root exists
- if ($this->pointer->node_type() == XML_DOCUMENT_NODE && $this->xml->document_element()) {
- if (!is_null($in_xpathQuery) && !$in_movePointer) {
- $this->_restore_bookmark();
- }
-
- return PEAR::raiseError(null, XML_DUPLICATE_ROOT, null, E_USER_WARNING, null, 'XML_XPath_Error', true);
- }
-
- if (XML_XPath::isError($importedNodes = $this->_build_fragment($in_xmlData))) {
- return $importedNodes;
- }
-
- foreach($importedNodes as $index => $importedNode) {
- $node = $this->pointer->append_child($importedNode);
- if ($index == 0) {
- $newNode = $node;
- }
- }
-
- if (!is_null($in_xpathQuery) && !$in_movePointer) {
- $this->_restore_bookmark();
- }
-
- return $newNode;
- }
-
- // }}}
- // {{{ object insertBefore()
-
- /**
- * Inserts the node before the current pointer.
- *
- * @param mixed $in_xmlData either a document fragment xml string or a node
- * @param string $in_xpathQuery (optional) quick xpath query
- * @param boolean $in_movePointer (optional) move internal pointer
- *
- * @access public
- * @return object pointer to the first of the new inserted nodes
- */
- function insertBefore($in_xmlData, $in_xpathQuery = null, $in_movePointer = false)
- {
- if (!$this->pointer) {
- return PEAR::raiseError(null, XML_XPATH_NULL_POINTER, null, E_USER_WARNING, '', 'XML_XPath_Error', true);
- }
-
- if (XML_XPath::isError($result = $this->_quick_evaluate_init($in_xpathQuery, $in_movePointer, array(XML_ELEMENT_NODE)))) {
- return $result;
- }
-
- // we do some fance stuff here to make this general...make a fake node
- $importedNodes = $this->_build_fragment($in_xmlData);
- if (XML_XPath::isError($importedNodes)) {
- return $importedNodes;
- }
-
- $parent = $this->pointer->parent_node();
- foreach($importedNodes as $index => $importedNode) {
- $node = $parent->insert_before($importedNode, $this->pointer);
- if ($index == 0) {
- $newNode = $node;
- }
- }
-
- if (!is_null($in_xpathQuery) && !$in_movePointer) {
- $this->_restore_bookmark();
- }
-
- return $newNode;
- }
-
- // }}}
- // {{{ object removeChild()
-
- /**
- * Removes the child node at the current pointer and returns it.
- *
- * This function will remove a child from the list of children and will
- * move the pointer to the parent node.
- *
- * @param string $in_xpathQuery (optional) quick xpath query
- * @param boolean $in_movePointer (optional) move internal pointer
- *
- * @access public
- * @return object cloned node of the removed node, ready to be put in another document
- */
- function removeChild($in_xpathQuery = null, $in_movePointer = false)
- {
- if (!$this->pointer) {
- return PEAR::raiseError(null, XML_XPATH_NULL_POINTER, null, E_USER_WARNING, '', 'XML_XPath_Error', true);
- }
-
- if (XML_XPath::isError($result = $this->_quick_evaluate_init($in_xpathQuery, $in_movePointer, array(XML_ELEMENT_NODE, XML_TEXT_NODE, XML_COMMENT_NODE, XML_PI_NODE, XML_CDATA_SECTION_NODE)))) {
- return $result;
- }
-
- // get the parent
- $parent = $this->pointer->parent_node();
- // remove the child
- $removedNode = $parent->remove_child($this->pointer);
- // set pointer to the parent
- $this->pointer = $parent;
-
- if (!is_null($in_xpathQuery) && !$in_movePointer) {
- $this->_restore_bookmark();
- }
-
- return new XML_XPath_result(array($removedNode), XPATH_NODESET, null, $this->ctx, $this->xml);
- }
-
- // }}}
- // {{{ object cloneNode()
-
- /**
- * Clones the node and return the node as a result object
- *
- * @param bool $in_deep (optional) clone node children
- * @param string $in_xpathQuery (optional) quick xpath query
- * @param boolean $in_movePointer (optional) move internal pointer
- *
- * @access public
- * @return object cloned node of the current node, ready to be put in another document
- */
- function cloneNode($in_deep = false, $in_xpathQuery = null, $in_movePointer = false)
- {
- if (!$this->pointer) {
- return PEAR::raiseError(null, XML_XPATH_NULL_POINTER, null, E_USER_WARNING, '', 'XML_XPath_Error', true);
- }
-
- if (XML_XPath::isError($result = $this->_quick_evaluate_init($in_xpathQuery, $in_movePointer))) {
- return $result;
- }
-
- $clonedNode = $this->pointer->clone_node($in_deep);
-
- if (!is_null($in_xpathQuery) && !$in_movePointer) {
- $this->_restore_bookmark();
- }
-
- return new XML_XPath_result(array($clonedNode), XPATH_NODESET, null, $this->ctx, $this->xml);
- }
- // }}}
- // {{{ void replaceChildren()
-
- /**
- * Not in the DOM specification, but certainly a convenient function. Allows you to pass
- * in an xml document fragment which will be parsed into an xml object and merged into the
- * xml document, replacing all the previous children of the node. It does this by shallow
- * cloning the node, restoring the attributes and then adding the parsed children.
- *
- * @param string $in_fragment xml fragment which will be merged into tree
- * @param string $in_xpathQuery (optional) quick xpath query
- * @param boolean $in_movePointer (optional) move internal pointer
- *
- * @access public
- * @return void {or XML_XPath_Error exception}
- */
- function replaceChildren($in_xmlData, $in_xpathQuery = null, $in_movePointer = false)
- {
- if (!$this->pointer) {
- return PEAR::raiseError(null, XML_XPATH_NULL_POINTER, null, E_USER_WARNING, '', 'XML_XPath_Error', true);
- }
-
- if (XML_XPath::isError($result = $this->_quick_evaluate_init($in_xpathQuery, $in_movePointer, array(XML_ELEMENT_NODE)))) {
- return $result;
- }
-
- if (XML_XPath::isError($importedNodes = $this->_build_fragment($in_xmlData))) {
- if (!is_null($in_xpathQuery) && !$in_movePointer) {
- $this->_restore_bookmark();
- }
-
- return $importedNodes;
- }
-
- // nix all the children by overwriting node and fixing attributes
- $attributes = $this->pointer->has_attributes() ? $this->pointer->attributes() : array();
- $this->pointer->replace_node($clone = $this->pointer->clone_node());
- $this->pointer = $clone;
-
- foreach($attributes as $attributeNode) {
- // waiting on set_attribute_node() to work here
- $this->pointer->set_attribute($attributeNode->node_name(), $attributeNode->value());
- }
-
- foreach ($importedNodes as $importedNode) {
- $this->pointer->append_child($importedNode);
- }
-
- if (!is_null($in_xpathQuery) && !$in_movePointer) {
- $this->_restore_bookmark();
- }
- }
-
- // }}}
- // {{{ string dumpChildren()
-
- /**
- * Returns all the contents of an element node, regardless of type, as is.
- *
- * @param string $in_xpathQuery quick xpath query
- * @param boolean $in_movePointer move internal pointer
- *
- * @access public
- * @return string xml string, a concatenation of all the children of the element node
- */
- function dumpChildren($in_xpathQuery = null, $in_movePointer = false, $in_format = true)
- {
- if (!$this->pointer) {
- return PEAR::raiseError(null, XML_XPATH_NULL_POINTER, null, E_USER_WARNING, '', 'XML_XPath_Error', true);
- }
-
- if (XML_XPath::isError($result = $this->_quick_evaluate_init($in_xpathQuery, $in_movePointer, array(XML_ELEMENT_NODE)))) {
- return $result;
- }
-
- $xmlString = trim($this->xml->dump_node($this->pointer, $in_format));
- $xmlString = substr($xmlString,strpos($xmlString,'>')+1,-(strlen($this->nodeName())+3));
-
- if (!is_null($in_xpathQuery) && !$in_movePointer) {
- $this->_restore_bookmark();
- }
-
- return $xmlString;
- }
-
- // }}}
- // {{{ void toFile()
-
- /**
- * Exports the xml document to a file. Only works for the whole document right now.
- *
- * @param file $in_file file to export the xml to
- * @param int $in_compression (optional) ratio of compression using zlib (0-9)
- *
- * @access public
- * @return void {or XML_XPath_Error exception}
- */
- function toFile($in_file, $in_compression = 0)
- {
- // If the file does not exist, make sure we can write in this directory
- if (!file_exists($in_file)) {
- if (!is_writable(dirname($in_file))) {
- return PEAR::raiseError(null, XML_XPATH_FILE_NOT_WRITABLE, null, E_USER_WARNING, "File: $in_file", 'XML_XPath_Error', true);
- }
- }
- // If the file exists, make sure we can overwrite it
- else {
- if (!is_writable($in_file)) {
- return PEAR::raiseError(null, XML_XPATH_FILE_NOT_WRITABLE, null, E_USER_WARNING, "File: $in_file", 'XML_XPath_Error', true);
- }
- }
-
- if (!(is_int($in_compression) && $in_compression >= 0 && $in_compression <= 9)) {
- $in_compression = 0;
- }
- $this->xml->dump_mem_file($in_file, $in_compression);
- return true;
- }
-
- // }}}
- // {{{ string toString()
-
- /**
- * Export the xml document to a string, beginning from the pointer.
- *
- * @param string $in_xpathQuery quick xpath query
- * @param boolean $in_movePointer move internal pointer
- * @param boolean $in_format reformat using xmllint --format
- *
- * @access public
- * @return string xml string, starting at pointer
- */
- function toString($in_xpathQuery = null, $in_movePointer = false, $in_format = true)
- {
- if (!$this->pointer) {
- return PEAR::raiseError(null, XML_XPATH_NULL_POINTER, null, E_USER_WARNING, '', 'XML_XPath_Error', true);
- }
-
- if ($hasQuery = !is_null($in_xpathQuery) && XML_XPath::isError($result = $this->_quick_evaluate_init($in_xpathQuery, $in_movePointer))) {
- return $result;
- }
-
- if ($this->nodeType() == XML_DOCUMENT_NODE) {
- $xmlString = $this->xml->dump_mem($in_format);
- }
- else {
- $xmlString = $this->xml->dump_node($this->pointer, $in_format);
- }
- /*
- if ($in_format) {
- $xmlString = escapeshellarg($xmlString);
- $xmlString = `echo $xmlString | {$this->xmllint} --format - 2>&1`;
- }*/
-
- if ($hasQuery && !$in_movePointer) {
- $this->_restore_bookmark();
- }
-
- return $xmlString;
- }
-
- // }}}
- // {{{ object getPointer()
-
- /**
- * Get the current pointer in the xml document.
- *
- * @access public
- * @return object current pointer object
- */
- function getPointer()
- {
- return $this->pointer;
- }
-
- // }}}
- // {{{ object setPointer()
-
- /**
- * Set the pointer in the xml document
- *
- * @param object $in_node node to move to in the xml document
- *
- * @access public
- * @return void {or XML_XPath_Error exception}
- */
- function setPointer($in_node)
- {
- // if this is an error object, just return it
- if (XML_XPath::isError($in_node)) {
- return $in_node;
- }
- elseif (!$this->_is_dom_node($in_node)) {
- return PEAR::raiseError(null, XML_XPATH_NODE_REQUIRED, null, E_USER_WARNING, $in_node, 'XML_XPath_Error', true);
- }
- else {
- // we are okay, set the node and return true
- $this->pointer = $in_node;
- return true;
- }
- }
-
- // }}}
- // {{{ string getNodePath()
-
- /**
- * Resolve the xpath location of the current node
- *
- * @param string $in_xpathQuery (optional)
- * @param boolean $in_movePointer (optional)
- *
- * @return string xpath location query
- * @access public
- */
- function getNodePath($in_node)
- {
- if (!$in_node) {
- return null;
- }
- elseif (!$this->_is_dom_node($in_node)) {
- return PEAR::raiseError(null, XML_XPATH_NODE_REQUIRED, null, E_USER_WARNING, $in_node, 'XML_XPath_Error', true);
- }
-
- $buffer = '';
- $cur = $in_node;
- do {
- $name = '';
- $sep = '/';
- $occur = 0;
- if (($type = $cur->node_type()) == XML_DOCUMENT_NODE) {
- if ($buffer[0] == '/') {
- break;
- }
-
- $next = false;
- }
- else if ($type == XML_ATTRIBUTE_NODE) {
- $sep .= '@';
- $name = $cur->node_name();
- $next = $cur->parent_node();
- }
- else {
- $name = $cur->node_name();
- $next = $cur->parent_node();
-
- // now figure out the index
- $tmp = $cur->previous_sibling();
- while ($tmp != false) {
- if ($name == $tmp->node_name()) {
- $occur++;
- }
- $tmp = $tmp->previous_sibling();
- }
-
- $occur++;
-
- if ($type == XML_ELEMENT_NODE) {
- // this is a hack and only works for some cases
- // we can have to nodes with the same name but different namespace,
- // so this should actually go above
- if (($prefix = $cur->prefix()) != '') {
- $name = $prefix . ':' . $name;
- }
- }
- // fix the names for those nodes where xpath query and dom node name don't match
- elseif ($type == XML_COMMENT_NODE) {
- $name = 'comment()';
- }
- elseif ($type == XML_PI_NODE) {
- $name = 'processing-instruction()';
- }
- elseif ($type == XML_TEXT_NODE) {
- $name = 'text()';
- }
- // anything left here has not been coded yet (cdata is broken)
- else {
- $name = '';
- $sep = '';
- $occur = 0;
- }
- }
-
- if ($occur == 0) {
- $buffer = $sep . $name . $buffer;
- }
- else {
- $buffer = $sep . $name . '[' . $occur . ']' . $buffer;
- }
-
- $cur = $next;
-
- } while ($cur != false);
-
- return $buffer;
- }
-
- // }}}
- // {{{ mixed getOne()
-
- /**
- * A quick version of the evaluate, where the results are returned immediately. This
- * function is equivalent to xsl:value-of select in every way.
- *
- * @param string $in_xpathQuery (optional) quick xpath query
- * @param boolean $in_movePointer (optional) move internal pointer
- *
- * @access public
- * @return mixed number of nodes or value of scalar result {or XML_XPath_Error exception}
- */
- function getOne($in_xpathQuery, $in_movePointer = false)
- {
- // Execute the xpath query and return the results, then reset the result index
- if (XML_XPath::isError($result = $this->evaluate($in_xpathQuery, $in_movePointer))) {
- return $result;
- }
-
- return $result->getData();
- }
-
- // }}}
- // {{{ void evaluate()
-
- /**
- * Evaluate the xpath expression on the loaded xml document.
- *
- * The xpath query provided is evaluated and either an XML_XPath_result object is
- * returned, or, if the pointer is being moved, it acts like a glorified step function
- * and moves the pointer to the specified node (or first node if it is a set) and returns
- * a boolean success
- *
- * @param string $in_xpathQuery xpath query
- * @param boolean $in_movePointer (optional) move internal pointer
- *
- * @access public
- * @return mixed result object or boolean success (for move pointer)
- * @throws XML_XPath_error XML_XPATH_NOT_LOADED
- */
- function &evaluate($in_xpathQuery, $in_movePointer = false)
- {
- // Make sure we have loaded an xml document and were able to create an xpath context
- if (strtolower(get_class($this->ctx)) != 'xpathcontext') {
- return PEAR::raiseError(null, XML_XPATH_NOT_LOADED, null, E_USER_ERROR, null, 'XML_XPath_Error', true);
- }
-
- // enable relative xpath queries (I don't check a valid dom object yet)
- settype($in_xpathQuery, 'array');
- if (isset($in_xpathQuery[1])) {
- $sep = '/';
- // those double slashes cause an anomally
- if (substr($in_xpathQuery[1], 0, 2) == '//') {
- $sep = '';
- }
-
- if ($in_xpathQuery[0] == 'current()' || $in_xpathQuery[0] == '.') {
- $in_xpathQuery[0] = $this->getNodePath($this->pointer);
- }
- elseif ($in_xpathQuery[0] == 'parent::node()' || $in_xpathQuery[0] == '..') {
- if ($this->pointer->node_type() != XML_DOCUMENT_NODE) {
- $in_xpathQuery[0] = $this->getNodePath($this->pointer->parent_node());
- }
- else {
- $in_xpathQuery[0] = $this->getNodePath($this->pointer);
- }
- }
- else {
- $in_xpathQuery[0] = $this->getNodePath($in_xpathQuery[0]);
- }
-
- // handle or statements and construct query
- $parts = explode('|', $in_xpathQuery[1]);
- $xpathQuery = $in_xpathQuery[0] . $sep . implode('|' . $in_xpathQuery[0] . $sep, $parts);
- }
- else {
- $xpathQuery = reset($in_xpathQuery);
- }
-
- // we don't care if this messes up, we will let the result object handle no results
- $result = @xpath_eval($this->ctx, $xpathQuery);
-
- // if we are moving the pointer, return boolean success just like the step functions
- if ($in_movePointer) {
- if ($result->type == XPATH_NODESET && !empty($result->nodeset)) {
- $this->pointer = reset($result->nodeset);
- return true;
- }
- else {
- return false;
- }
- }
-
- $ret = new XML_XPath_result(
- $result->type == XPATH_NODESET ? $result->nodeset : $result->value,
- $result->type,
- $xpathQuery,
- $this->ctx,
- $this->xml
- );
- return $ret;
- }
-
- // }}}
- // {{{ _build_fragment()
-
- /**
- * For functions which take a document fragment I have a general way to import the data
- * into a nodeset and then I return the nodeset. If the xml data was already a node, I
- * just cast it to a single element array so the return type is consistent.
- *
- * @param mixed $in_xmlData either document fragment string or dom node
- *
- * @access private
- * @return array nodeset array
- */
- function _build_fragment($in_xmlData)
- {
- if ($this->_is_dom_node($in_xmlData)) {
- $fakeChildren = array($in_xmlData);
- }
- else {
- $fake = @domxml_open_mem('<fake>'.$in_xmlData.'</fake>');
- if (!$fake) {
- return PEAR::raiseError(null, XML_PARSE_ERROR, null, E_USER_WARNING, $in_xmlData, 'XML_XPath_Error', true);
- }
- $fakeRoot = $fake->document_element();
- $fakeChildren = $fakeRoot->has_child_nodes() ? $fakeRoot->child_nodes() : array();
- }
- return $fakeChildren;
- }
-
- // }}}
- // {{{ _set_content()
-
- /**
- * Generic function to handle manipulation of a data string based on manipulation parameters.
- *
- * @param string $in_content data to be added
- * @param boolean $in_replace method of manipulation
- * @param int $in_offset offset of manipulation
- * @param int $in_count length of manipulation
- *
- * @access private
- * @return object XML_XPath_Error on fail
- */
- function _set_content($in_content, $in_xpathQuery, $in_movePointer, $in_replace, $in_offset = 0, $in_count = 0)
- {
- if (!$this->pointer) {
- return PEAR::raiseError(null, XML_XPATH_NULL_POINTER, null, E_USER_WARNING, '', 'XML_XPath_Error', true);
- }
-
- if (XML_XPath::isError($result = $this->_quick_evaluate_init($in_xpathQuery, $in_movePointer, array(XML_ELEMENT_NODE, XML_TEXT_NODE, XML_CDATA_SECTION_NODE, XML_COMMENT_NODE, XML_PI_NODE)))) {
- return $result;
- }
-
- $data = $this->pointer->get_content();
- // little hack to get appendData to use this function here...special little exception
- $in_offset = is_null($in_offset) ? strlen($data) : $in_offset;
- if (!is_int($in_offset) || $in_offset < 0 || $in_offset > strlen($data)) {
- $return = PEAR::raiseError(null, XML_XPATH_INDEX_SIZE, null, E_USER_WARNING, "Offset: $in_offset", 'XML_XPath_Error', true);
- }
- elseif (!is_int($in_count) || $in_count < 0) {
- $return = PEAR::raiseError(null, XML_XPATH_INDEX_SIZE, null, E_USER_WARNING, "Count: $in_offset", 'XML_XPath_Error', true);
- }
- else {
- if ($in_replace) {
- $data = $in_count ? substr($data, 0, $in_offset) . $in_content . substr($data, $in_offset + $in_count) : substr($data, 0, $in_offset) . $in_content;
- }
- else {
- $data = substr($data, 0, $in_offset) . $in_content . substr($data, $in_offset);
- }
-
- if ($this->pointer->node_type() == XML_ELEMENT_NODE) {
- $this->replaceChildren($data);
- }
- else {
- $this->pointer->replace_node($this->xml->create_text_node($data));
- }
-
- $return = null;
- }
-
- if (!is_null($in_xpathQuery) && !$in_movePointer) {
- $this->_restore_bookmark();
- }
-
- return $return;
- }
-
- // }}}
- // {{{ _is_dom_node()
-
- /**
- * Determines if the provided object is a domnode descendent.
- *
- * @param object $in_object object in question
- *
- * @access private
- * @return boolean whether the object is a domnode
- */
- function _is_dom_node($in_object)
- {
- return (is_object($in_object) && is_a_php_class($in_object, 'domnode'));
- }
-
- // }}}
- // {{{ _restore_bookmark()
-
- /**
- * Restore the internal pointer after a quick query operation
- *
- * @access private
- * @return void
- */
- function _restore_bookmark()
- {
- $this->pointer = $this->bookmark;
- }
-
- // }}}
- // {{{ _quick_evaluate_init()
-
- /**
- * The function will allow an on the quick xpath query to move the internal pointer before
- * invoking the xmldom function. The requirements are that the xpath query must return
- * an XPATH_NODESET and have at least one node. If not, an XML_XPath_Error will be returned
- * ** In addition this function does a check on the correct nodeType to run the caller method
- *
- * @param string $in_xpathQuery optional xpath query to move the internal pointer
- * @param boolean $in_movePointer move the pointer temporarily or permanently
- * @param array $in_nodeTypes required nodeType list for the caller method
- *
- * @access private
- * @return boolean true on success, XML_XPath_Error on error
- */
- function _quick_evaluate_init($in_xpathQuery = null, $in_movePointer = false, $in_nodeTypes = null)
- {
- // we don't need to check for null, since false or 0 is not a valid query anyway
- if ($in_xpathQuery) {
- if (!is_object($in_xpathQuery)) {
- // doing the following manually (without evaluate()) is critical for speed
-
- // Make sure we have an xpath context (mildly costly)
- if (strtolower(get_class($this->ctx)) != 'xpathcontext') {
- return PEAR::raiseError(null, XML_XPATH_NOT_LOADED, null, E_USER_ERROR, null, 'XML_XPath_Error', true);
- }
-
- // enable relative xpath queries (I don't check a valid dom object yet)
- settype($in_xpathQuery, 'array');
- if (isset($in_xpathQuery[1])) {
- $sep = '/';
- // those double slashes cause an anomally
- if (substr($in_xpathQuery[1], 0, 2) == '//') {
- $sep = '';
- }
-
- if ($in_xpathQuery[0] == 'current()' || $in_xpathQuery[0] == '.') {
- $in_xpathQuery[0] = $this->getNodePath($this->pointer);
- }
- elseif ($in_xpathQuery[0] == 'parent::node()' || $in_xpathQuery[0] == '..') {
- if ($this->pointer->node_type() != XML_DOCUMENT_NODE) {
- $in_xpathQuery[0] = $this->getNodePath($this->pointer->parent_node());
- }
- else {
- $in_xpathQuery[0] = $this->getNodePath($this->pointer);
- }
- }
- else {
- $in_xpathQuery[0] = $this->getNodePath($in_xpathQuery[0]);
- }
-
- $xpathQuery = $in_xpathQuery[0] . $sep . $in_xpathQuery[1];
- }
- else {
- $xpathQuery = reset($in_xpathQuery);
- }
-
- if (!$result = @xpath_eval($this->ctx, $xpathQuery)) {
- return PEAR::raiseError(null, XML_XPATH_INVALID_QUERY, null, E_USER_WARNING, "XML_XPath query: $xpathQuery", 'XML_XPath_Error', true);
- }
-
- if (empty($result->nodeset) || $result->type != XPATH_NODESET) {
- return PEAR::raiseError(null, XML_XPATH_INVALID_NODESET, null, E_USER_WARNING, "XML_XPath query: $xpathQuery", 'XML_XPath_Error', true);
- }
-
- // this takes the first result (too bad if you had more)
- $tmpPointer = reset($result->nodeset);
- }
- // a bit costly, so we put it second
- elseif ($this->_is_dom_node($in_xpathQuery)) {
- $tmpPointer = $in_xpathQuery;
- }
- else {
- return PEAR::raiseError(null, XML_XPATH_INVALID_QUERY, null, E_USER_WARNING, "XML_XPath query: $in_xpathQuery", 'XML_XPath_Error', true);
- }
-
- // if we are moving the internal pointer, then do it now
- if ($in_movePointer) {
- $this->pointer = $tmpPointer;
- }
- // set the bookmark if we only want to temporarily move the pointer
- // this area is too critical to call class methods...we have to be nasty
- else {
- $this->bookmark = $this->pointer;
- $this->pointer = $tmpPointer;
- }
- }
-
- // see if we have a restricted nodeType requirement (negligible time)
- if (is_array($in_nodeTypes) && !in_array($nodeType = $this->pointer->node_type(), $in_nodeTypes)) {
- if (!is_null($in_xpathQuery) && !$in_movePointer) {
- $this->_restore_bookmark();
- }
-
- return PEAR::raiseError(null, XML_XPATH_INVALID_NODETYPE, null, E_USER_WARNING, "Required type: ".implode(" or ", $in_nodeTypes).", Provided type: ".$nodeType, 'XML_XPath_Error', true);
- }
- else {
- return true;
- }
- }
-
- // }}}
- }
- ?>
-