Current File : //opt/RZphp73/includes/XML/XPath/common.php |
<?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;
}
}
// }}}
}
?>