git-svn-id: https://192.168.0.254/svn/Proyectos.FundacionLQDVI_WebCongresos/trunk@2 94ccb1af-fd9d-d947-8d90-7f70ea60afc8
1048 lines
32 KiB
PHP
1048 lines
32 KiB
PHP
<?php
|
|
/**
|
|
* @package domit-xmlparser
|
|
* @subpackage domit-xmlparser-main
|
|
* @copyright (C) 2004 John Heinstein. All rights reserved
|
|
* @license http://www.gnu.org/copyleft/lesser.html LGPL License
|
|
* @author John Heinstein <johnkarl@nbnet.nb.ca>
|
|
* @link http://www.engageinteractive.com/domit/ DOMIT! Home Page
|
|
* DOMIT! is Free Software
|
|
**/
|
|
|
|
if (!defined('DOMIT_INCLUDE_PATH')) {
|
|
define('DOMIT_INCLUDE_PATH', (dirname(__FILE__) . "/"));
|
|
}
|
|
|
|
/** Separator for absolute path */
|
|
define('DOMIT_XPATH_SEPARATOR_ABSOLUTE', '/');
|
|
/** Separator for relative path */
|
|
define('DOMIT_XPATH_SEPARATOR_RELATIVE', '//');
|
|
/** OR separator for multiple patterns */
|
|
define('DOMIT_XPATH_SEPARATOR_OR', '|');
|
|
|
|
/** Constant for an absolute path search (starting at the document root) */
|
|
define('DOMIT_XPATH_SEARCH_ABSOLUTE', 0);
|
|
/** Constant for a relative path search (starting at the level of the calling node) */
|
|
define('DOMIT_XPATH_SEARCH_RELATIVE', 1);
|
|
/** Constant for a variable path search (finds all matches, regardless of place in the hierarchy) */
|
|
define('DOMIT_XPATH_SEARCH_VARIABLE', 2);
|
|
|
|
|
|
/**
|
|
* DOMIT! XPath is an XPath parser.
|
|
*/
|
|
class DOMIT_XPath {
|
|
/** @var Object The node from which the search is called */
|
|
var $callingNode;
|
|
/** @var Object The node that is the current parent of the search */
|
|
var $searchType;
|
|
/** @var array An array containing a series of path segments for which to search */
|
|
var $arPathSegments = array();
|
|
/** @var Object A DOMIT_NodeList of matching nodes */
|
|
var $nodeList;
|
|
/** @var string A temporary string container */
|
|
var $charContainer;
|
|
/** @var string The current character of the current pattern segment being parsed */
|
|
var $currChar;
|
|
/** @var string The current pattern segment being parsed */
|
|
var $currentSegment;
|
|
/** @var array A temporary node container for caching node references at the pattern level*/
|
|
var $globalNodeContainer;
|
|
/** @var array A temporary node container for caching node references at the pattern segment level */
|
|
var $localNodeContainer;
|
|
/** @var array Normalization table for XPath syntax */
|
|
var $normalizationTable = array('child::' => '', 'self::' => '.',
|
|
'attribute::' => '@', 'descendant::' => '*//',
|
|
"\t" => ' ', "\x0B" => ' ');
|
|
/** @var array A second-pass normalization table for XPath syntax */
|
|
var $normalizationTable2 = array(' =' => '=', '= ' => '=', ' <' => '<',
|
|
' >' => '>', '< ' => '<', '> ' => '>',
|
|
' !' => '!', '( ' => '(',
|
|
' )' => ')', ' ]' => ']', '] ' => ']',
|
|
' [' => '[', '[ ' => '[', ' /' => '/',
|
|
'/ ' => '/', '"' => "'");
|
|
/** @var array A third-pass normalization table for XPath syntax */
|
|
var $normalizationTable3 = array('position()=' => '',
|
|
'/descendant-or-self::node()/' => "//", 'self::node()' => '.',
|
|
'parent::node()' => '..');
|
|
|
|
/**
|
|
* Constructor - creates an empty DOMIT_NodeList to store matching nodes
|
|
*/
|
|
function DOMIT_XPath() {
|
|
require_once(DOMIT_INCLUDE_PATH . 'xml_domit_nodemaps.php');
|
|
$this->nodeList = new DOMIT_NodeList();
|
|
} //DOMIT_XPath
|
|
|
|
/**
|
|
* Parses the supplied "path"-based pattern
|
|
* @param Object The node from which the search is called
|
|
* @param string The pattern
|
|
* @return Object The NodeList containing matching nodes
|
|
*/
|
|
function &parsePattern(&$node, $pattern, $nodeIndex = 0) {
|
|
$this->callingNode =& $node;
|
|
$pattern = $this->normalize(trim($pattern));
|
|
|
|
$this->splitPattern($pattern);
|
|
|
|
$total = count($this->arPathSegments);
|
|
|
|
//whole pattern level
|
|
for ($i = 0; $i < $total; $i++) {
|
|
$outerArray =& $this->arPathSegments[$i];
|
|
$this->initSearch($outerArray);
|
|
|
|
$outerTotal = count($outerArray);
|
|
$isInitialMatchAttempt = true;
|
|
|
|
//variable path segment level
|
|
for ($j = 0; $j < $outerTotal; $j++) {
|
|
$innerArray =& $outerArray[$j];
|
|
$innerTotal = count($innerArray);
|
|
|
|
if (!$isInitialMatchAttempt) {
|
|
$this->searchType = DOMIT_XPATH_SEARCH_VARIABLE;
|
|
}
|
|
|
|
//pattern segment level
|
|
for ($k = 0; $k < $innerTotal; $k++) {
|
|
$currentPattern = $innerArray[$k];
|
|
|
|
if (($k == 0) && ($currentPattern == null)) {
|
|
if ($innerTotal == 1) {
|
|
$isInitialMatchAttempt = false;
|
|
}
|
|
//else just skip current step and don't alter searchType
|
|
}
|
|
else {
|
|
if (!$isInitialMatchAttempt && ($k > 0)) {
|
|
$this->searchType = DOMIT_XPATH_SEARCH_RELATIVE;
|
|
}
|
|
|
|
$this->currentSegment = $currentPattern;
|
|
$this->processPatternSegment();
|
|
$isInitialMatchAttempt = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($nodeIndex > 0) {
|
|
if ($nodeIndex <= count($this->globalNodeContainer)) {
|
|
return $this->globalNodeContainer[($nodeIndex - 1)];
|
|
}
|
|
else {
|
|
$null = null;
|
|
return $null;
|
|
}
|
|
}
|
|
|
|
if (count($this->globalNodeContainer) != 0) {
|
|
foreach ($this->globalNodeContainer as $key =>$value) {
|
|
$currNode =& $this->globalNodeContainer[$key];
|
|
$this->nodeList->appendNode($currNode);
|
|
}
|
|
}
|
|
|
|
return $this->nodeList;
|
|
} //parsePattern
|
|
|
|
/**
|
|
* Generates a new globalNodeContainer of matches
|
|
*/
|
|
function processPatternSegment() {
|
|
$total = strlen($this->currentSegment);
|
|
$this->charContainer = '';
|
|
$this->localNodeContainer = array();
|
|
|
|
for ($i = 0; $i < $total; $i++) {
|
|
// $this->currChar = $this->currentSegment{$i};
|
|
$this->currChar = substr($this->currentSegment, $i, 1);
|
|
|
|
switch ($this->currChar) {
|
|
case '@':
|
|
$this->selectAttribute(substr($this->currentSegment, ($this->currChar + 1)));
|
|
$this->updateNodeContainers();
|
|
return;
|
|
//break;
|
|
|
|
case '*':
|
|
if ($i == ($total - 1)) {
|
|
$this->selectNamedChild('*');
|
|
}
|
|
else {
|
|
$this->charContainer .= $this->currChar;
|
|
}
|
|
break;
|
|
|
|
case '.':
|
|
$this->charContainer .= $this->currChar;
|
|
|
|
if ($i == ($total - 1)) {
|
|
if ($this->charContainer == '..') {
|
|
$this->selectParent();
|
|
}
|
|
else {
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ')':
|
|
$this->charContainer .= $this->currChar;
|
|
$this->selectNodesByFunction();
|
|
break;
|
|
|
|
case '[':
|
|
$this->parsePredicate($this->charContainer,
|
|
substr($this->currentSegment, ($i + 1)));
|
|
return;
|
|
//break;
|
|
|
|
default:
|
|
$this->charContainer .= $this->currChar;
|
|
|
|
}
|
|
}
|
|
|
|
if ($this->charContainer != '') {
|
|
$this->selectNamedChild($this->charContainer);
|
|
}
|
|
|
|
$this->updateNodeContainers();
|
|
} //processPatternSegment
|
|
|
|
/**
|
|
* Replaces the global node container with the local node container
|
|
*/
|
|
function updateNodeContainers() {
|
|
$this->globalNodeContainer =& $this->localNodeContainer;
|
|
unset($this->localNodeContainer);
|
|
} //updateNodeContainers
|
|
|
|
|
|
/**
|
|
* Parses a predicate expression [...]
|
|
* @param string The pattern segment containing the node expression
|
|
* @param string The pattern segment containing the predicate expression
|
|
*/
|
|
function parsePredicate($nodeName, $patternSegment) {
|
|
$arPredicates =& explode('][', $patternSegment);
|
|
|
|
$total = count($arPredicates);
|
|
|
|
$lastIndex = $total - 1;
|
|
$arPredicates[$lastIndex] = substr($arPredicates[$lastIndex],
|
|
0, (strlen($arPredicates[$lastIndex]) - 1));
|
|
|
|
for ($i = 0; $i < $total; $i++) {
|
|
$isRecursive = ($this->searchType == DOMIT_XPATH_SEARCH_VARIABLE) ? true : false;
|
|
$currPredicate = $arPredicates[$i];
|
|
|
|
if (is_numeric($currPredicate)) {
|
|
if ($i == 0) {
|
|
$this->filterByIndex($nodeName, intval($currPredicate), $isRecursive);
|
|
}
|
|
else {
|
|
$this->refilterByIndex(intval($currPredicate));
|
|
}
|
|
}
|
|
else {
|
|
if ($i == 0) {
|
|
$this->selectNamedChild($nodeName);
|
|
$this->updateNodeContainers();
|
|
}
|
|
|
|
$phpExpression = $this->predicateToPHP($currPredicate);
|
|
$this->filterByPHPExpression($phpExpression);
|
|
}
|
|
|
|
$this->updateNodeContainers();
|
|
}
|
|
|
|
$this->charContainer = '';
|
|
} //parsePredicate
|
|
|
|
/**
|
|
* Converts the predicate into PHP evaluable code
|
|
* @param string The predicate
|
|
* @return string The converted PHP expression
|
|
*/
|
|
function predicateToPHP($predicate) {
|
|
$phpExpression = $predicate;
|
|
$currChar = '';
|
|
$charContainer = '';
|
|
$totalChars = strlen($predicate);
|
|
|
|
for ($i = 0; $i < $totalChars; $i++) {
|
|
$currChar = substr($predicate, $i, 1);
|
|
|
|
switch ($currChar) {
|
|
case '(':
|
|
case ')':
|
|
case ' ':
|
|
if ($charContainer != '') {
|
|
$convertedPredicate = $this->expressionToPHP($charContainer);
|
|
$phpExpression = str_replace($charContainer, $convertedPredicate, $phpExpression);
|
|
$charContainer = '';
|
|
}
|
|
break;
|
|
|
|
default:
|
|
$charContainer .= $currChar;
|
|
|
|
}
|
|
}
|
|
|
|
if ($charContainer != '') {
|
|
$convertedPredicate = $this->expressionToPHP($charContainer);
|
|
$phpExpression = str_replace($charContainer, $convertedPredicate, $phpExpression);
|
|
}
|
|
|
|
return $phpExpression;
|
|
} //predicateToPHP
|
|
|
|
|
|
/**
|
|
* Converts the predicate expression into a PHP expression
|
|
* @param string The predicate expression
|
|
* @return string The converted PHP expression
|
|
*/
|
|
function expressionToPHP($expression) {
|
|
if ($expression == 'and') {
|
|
$expression = '&&';
|
|
}
|
|
else if ($expression == 'or') {
|
|
$expression = '||';
|
|
}
|
|
else if ($expression == 'not') {
|
|
$expression = '!';
|
|
}
|
|
else {
|
|
$expression = trim($expression);
|
|
|
|
if (strpos($expression, '@') !== false) {
|
|
if (strpos($expression, '>=') !== false) {
|
|
$expression = str_replace('@', ('floatval($' . "contextNode->getAttribute('"), $expression);
|
|
$expression = str_replace('>=', "')) >= floatval(", $expression);
|
|
if (!is_numeric($expression)) $expression = str_replace('floatval', '', $expression);
|
|
$expression .= ')';
|
|
}
|
|
else if (strpos($expression, '<=') !== false) {
|
|
$expression = str_replace('@', ('floatval($' . "contextNode->getAttribute('"), $expression);
|
|
$expression = str_replace('<=', "')) <= floatval(", $expression);
|
|
if (!is_numeric($expression)) $expression = str_replace('floatval', '', $expression);
|
|
$expression .= ')';
|
|
}
|
|
else if (strpos($expression, '!=') !== false) {
|
|
$expression = str_replace('@', ('$' . "contextNode->getAttribute('"), $expression);
|
|
$expression = str_replace('!=', "') != ", $expression);
|
|
}
|
|
else if (strpos($expression, '=') !== false) {
|
|
$expression = str_replace('@', ('$' . "contextNode->getAttribute('"), $expression);
|
|
$expression = str_replace('=', "') == ", $expression);
|
|
}
|
|
else if (strpos($expression, '>') !== false) {
|
|
$expression = str_replace('>', "')) > floatval(", $expression); //reverse so > doesn't get replaced
|
|
$expression = str_replace('@', ('floatval($' . "contextNode->getAttribute('"), $expression);
|
|
if (!is_numeric($expression)) $expression = str_replace('floatval', '', $expression);
|
|
$expression .= ')';
|
|
}
|
|
else if (strpos($expression, '<') !== false) {
|
|
$expression = str_replace('@', ('floatval($' . "contextNode->getAttribute('"), $expression);
|
|
$expression = str_replace('<', "')) < floatval(", $expression);
|
|
if (!is_numeric($expression)) $expression = str_replace('floatval', '', $expression);
|
|
$expression .= ')';
|
|
}
|
|
else {
|
|
$expression = str_replace('@', ('$' . "contextNode->hasAttribute('"), $expression);
|
|
$expression.= "')";
|
|
}
|
|
}
|
|
else {
|
|
if (strpos($expression, '>=') !== false) {
|
|
$signPos = strpos($expression, '>=');
|
|
$elementName = trim(substr($expression, 0, $signPos));
|
|
$elementValue = trim(substr($expression, ($signPos + 2)));
|
|
|
|
$expression = '$' . "this->hasNamedChildElementGreaterThanOrEqualToValue(" .
|
|
'$' . "contextNode, '" . $elementName . "', " .
|
|
$elementValue . ')';
|
|
}
|
|
else if (strpos($expression, '<=') !== false) {
|
|
$signPos = strpos($expression, '>=');
|
|
$elementName = trim(substr($expression, 0, $signPos));
|
|
$elementValue = trim(substr($expression, ($signPos + 2)));
|
|
|
|
$expression = '$' . "this->hasNamedChildElementLessThanOrEqualToValue(" .
|
|
'$' . "contextNode, '" . $elementName . "', " .
|
|
$elementValue . ')';
|
|
}
|
|
else if (strpos($expression, '!=') !== false) {
|
|
$signPos = strpos($expression, '>=');
|
|
$elementName = trim(substr($expression, 0, $signPos));
|
|
$elementValue = trim(substr($expression, ($signPos + 2)));
|
|
|
|
$expression = '$' . "this->hasNamedChildElementNotEqualToValue(" .
|
|
'$' . "contextNode, '" . $elementName . "', " .
|
|
$elementValue . ')';
|
|
}
|
|
else if (strpos($expression, '=') !== false) {
|
|
$signPos = strpos($expression, '=');
|
|
$elementName = trim(substr($expression, 0, $signPos));
|
|
$elementValue = trim(substr($expression, ($signPos + 1)));
|
|
|
|
$expression = '$' . "this->hasNamedChildElementEqualToValue(" .
|
|
'$' . "contextNode, '" . $elementName . "', " .
|
|
$elementValue . ')';
|
|
|
|
}
|
|
else if (strpos($expression, '>') !== false) {
|
|
$signPos = strpos($expression, '=');
|
|
$elementName = trim(substr($expression, 0, $signPos));
|
|
$elementValue = trim(substr($expression, ($signPos + 1)));
|
|
|
|
$expression = '$' . "this->hasNamedChildElementGreaterThanValue(" .
|
|
'$' . "contextNode, '" . $elementName . "', " .
|
|
$elementValue . ')';
|
|
}
|
|
else if (strpos($expression, '<') !== false) {
|
|
$signPos = strpos($expression, '=');
|
|
$elementName = trim(substr($expression, 0, $signPos));
|
|
$elementValue = trim(substr($expression, ($signPos + 1)));
|
|
|
|
$expression = '$' . "this->hasNamedChildElementLessThanValue(" .
|
|
'$' . "contextNode, '" . $elementName . "', " .
|
|
$elementValue . ')';
|
|
}
|
|
else {
|
|
$expression = '$' . "this->hasNamedChildElement(" .
|
|
'$' . "contextNode, '" . $expression . "')";
|
|
}
|
|
}
|
|
}
|
|
|
|
return $expression;
|
|
} //expressionToPHP
|
|
|
|
/**
|
|
* Selects nodes that match the predicate expression
|
|
* @param string The predicate expression, formatted as a PHP expression
|
|
*/
|
|
function filterByPHPExpression($expression) {
|
|
if (count($this->globalNodeContainer) != 0) {
|
|
foreach ($this->globalNodeContainer as $key =>$value) {
|
|
$contextNode =& $this->globalNodeContainer[$key];
|
|
|
|
if ($contextNode->nodeType == DOMIT_ELEMENT_NODE) {
|
|
$evaluatedExpression = 'if (' . $expression . ") $" .
|
|
'this->localNodeContainer[] =& $' . 'contextNode;';
|
|
eval($evaluatedExpression);
|
|
}
|
|
}
|
|
}
|
|
} //filterByPHPExpression
|
|
|
|
/**
|
|
* Selects nodes with child elements that match the specified name
|
|
* @param object The parent node of the child elements to match
|
|
* @param string The tag name to match on
|
|
* @return boolean True if a matching child element exists
|
|
*/
|
|
function hasNamedChildElement(&$parentNode, $nodeName) {
|
|
$total = $parentNode->childCount;
|
|
|
|
for ($i = 0; $i < $total; $i++) {
|
|
$currNode =& $parentNode->childNodes[$i];
|
|
|
|
if (($currNode->nodeType == DOMIT_ELEMENT_NODE) && ($currNode->nodeName == $nodeName)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
} //hasNamedChildElement
|
|
|
|
/**
|
|
* Selects nodes with child elements that match the specified name and text value
|
|
* @param object The parent node of the child elements to match
|
|
* @param string The tag name to match on
|
|
* @param string The text string to match on
|
|
* @return boolean True if a matching child element exists
|
|
*/
|
|
function hasNamedChildElementEqualToValue(&$parentNode, $nodeName, $nodeValue) {
|
|
$total = $parentNode->childCount;
|
|
|
|
for ($i = 0; $i < $total; $i++) {
|
|
$currNode =& $parentNode->childNodes[$i];
|
|
|
|
if (($currNode->nodeType == DOMIT_ELEMENT_NODE) &&
|
|
($currNode->nodeName == $nodeName) && ($currNode->getText() == $nodeValue)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
} //hasNamedChildElementEqualToValue
|
|
|
|
/**
|
|
* Selects nodes with child elements that are greater than or equal to the specified name and value
|
|
* @param object The parent node of the child elements to match
|
|
* @param string The tag name to match on
|
|
* @param string The text string to match on
|
|
* @return boolean True if a matching child element exists
|
|
*/
|
|
function hasNamedChildElementGreaterThanOrEqualToValue(&$parentNode, $nodeName, $nodeValue) {
|
|
$isNumeric = false;
|
|
|
|
if (is_numeric($nodeValue)) {
|
|
$isNumeric = true;
|
|
$nodeValue = floatval($nodeValue);
|
|
}
|
|
|
|
$total = $parentNode->childCount;
|
|
|
|
for ($i = 0; $i < $total; $i++) {
|
|
$currNode =& $parentNode->childNodes[$i];
|
|
|
|
if (($currNode->nodeType == DOMIT_ELEMENT_NODE) && ($currNode->nodeName == $nodeName)) {
|
|
if ($isNumeric) {$compareVal = floatval($currNode->getText());}
|
|
else {$compareVal = $currNode->getText();}
|
|
if ($compareVal >= $nodeValue) return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
} //hasNamedChildElementGreaterThanOrEqualToValue
|
|
|
|
|
|
/**
|
|
* Selects nodes with child elements that are less than or equal to the specified name and value
|
|
* @param object The parent node of the child elements to match
|
|
* @param string The tag name to match on
|
|
* @param string The text string to match on
|
|
* @return boolean True if a matching child element exists
|
|
*/
|
|
function hasNamedChildElementLessThanOrEqualToValue(&$parentNode, $nodeName, $nodeValue) {
|
|
$isNumeric = false;
|
|
|
|
if (is_numeric($nodeValue)) {
|
|
$isNumeric = true;
|
|
$nodeValue = floatval($nodeValue);
|
|
}
|
|
|
|
$total = $parentNode->childCount;
|
|
|
|
for ($i = 0; $i < $total; $i++) {
|
|
$currNode =& $parentNode->childNodes[$i];
|
|
|
|
if (($currNode->nodeType == DOMIT_ELEMENT_NODE) && ($currNode->nodeName == $nodeName)) {
|
|
if ($isNumeric) {$compareVal = floatval($currNode->getText());}
|
|
else {$compareVal = $currNode->getText();}
|
|
if ($compareVal <= $nodeValue) return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
} //hasNamedChildElementLessThanOrEqualToValue
|
|
|
|
/**
|
|
* Selects nodes with child elements that are not equal to the specified name and value
|
|
* @param object The parent node of the child elements to match
|
|
* @param string The tag name to match on
|
|
* @param string The text string to match on
|
|
* @return boolean True if a matching child element exists
|
|
*/
|
|
function hasNamedChildElementNotEqualToValue(&$parentNode, $nodeName, $nodeValue) {
|
|
$isNumeric = false;
|
|
|
|
if (is_numeric($nodeValue)) {
|
|
$isNumeric = true;
|
|
$nodeValue = floatval($nodeValue);
|
|
}
|
|
|
|
$total = $parentNode->childCount;
|
|
|
|
for ($i = 0; $i < $total; $i++) {
|
|
$currNode =& $parentNode->childNodes[$i];
|
|
|
|
if (($currNode->nodeType == DOMIT_ELEMENT_NODE) && ($currNode->nodeName == $nodeName)) {
|
|
if ($isNumeric) {$compareVal = floatval($currNode->getText());}
|
|
else {$compareVal = $currNode->getText();}
|
|
if ($compareVal != $nodeValue) return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
} //hasNamedChildElementNotEqualToValue
|
|
|
|
/**
|
|
* Selects nodes with child elements that are greater than the specified name and value
|
|
* @param object The parent node of the child elements to match
|
|
* @param string The tag name to match on
|
|
* @param string The text string to match on
|
|
* @return boolean True if a matching child element exists
|
|
*/
|
|
function hasNamedChildElementGreaterThanValue(&$parentNode, $nodeName, $nodeValue) {
|
|
$isNumeric = false;
|
|
|
|
if (is_numeric($nodeValue)) {
|
|
$isNumeric = true;
|
|
$nodeValue = floatval($nodeValue);
|
|
}
|
|
|
|
$total = $parentNode->childCount;
|
|
|
|
for ($i = 0; $i < $total; $i++) {
|
|
$currNode =& $parentNode->childNodes[$i];
|
|
|
|
if (($currNode->nodeType == DOMIT_ELEMENT_NODE) && ($currNode->nodeName == $nodeName)) {
|
|
if ($isNumeric) {$compareVal = floatval($currNode->getText());}
|
|
else {$compareVal = $currNode->getText();}
|
|
if ($compareVal > $nodeValue) return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
} //hasNamedChildElementGreaterThanValue
|
|
|
|
|
|
/**
|
|
* Selects nodes with child elements that are less than the specified name and value
|
|
* @param object The parent node of the child elements to match
|
|
* @param string The tag name to match on
|
|
* @param string The text string to match on
|
|
* @return boolean True if a matching child element exists
|
|
*/
|
|
function hasNamedChildElementLessThanValue(&$parentNode, $nodeName, $nodeValue) {
|
|
$isNumeric = false;
|
|
|
|
if (is_numeric($nodeValue)) {
|
|
$isNumeric = true;
|
|
$nodeValue = floatval($nodeValue);
|
|
}
|
|
|
|
$total = $parentNode->childCount;
|
|
|
|
for ($i = 0; $i < $total; $i++) {
|
|
$currNode =& $parentNode->childNodes[$i];
|
|
|
|
if (($currNode->nodeType == DOMIT_ELEMENT_NODE) && ($currNode->nodeName == $nodeName)) {
|
|
if ($isNumeric) {$compareVal = floatval($currNode->getText());}
|
|
else {$compareVal = $currNode->getText();}
|
|
if ($compareVal < $nodeValue) return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
} //hasNamedChildElementLessThanValue
|
|
|
|
/**
|
|
* Selects named elements of the specified index
|
|
* @param string The pattern segment containing the node expression
|
|
* @param int The index (base 1) of the matching node
|
|
* @param boolean True if the selection is to be performed recursively
|
|
*/
|
|
function refilterByIndex($index) {
|
|
if ($index > 1) {
|
|
if (count($this->globalNodeContainer) != 0) {
|
|
$counter = 0;
|
|
$lastParentID = null;
|
|
|
|
foreach ($this->globalNodeContainer as $key =>$value) {
|
|
$currNode =& $this->globalNodeContainer[$key];
|
|
|
|
if (($lastParentID != null) && ($currNode->parentNode->uid != $lastParentID)) {
|
|
$counter = 0;
|
|
}
|
|
|
|
$counter++;
|
|
|
|
if (($counter == $index) && ($currNode->parentNode->uid == $lastParentID)) {
|
|
$this->localNodeContainer[] =& $currNode;
|
|
}
|
|
|
|
$lastParentID = $currNode->parentNode->uid;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
$this->localNodeContainer =& $this->globalNodeContainer;
|
|
}
|
|
} //refilterByIndex
|
|
|
|
|
|
/**
|
|
* Selects named elements of the specified index
|
|
* @param string The pattern segment containing the node expression
|
|
* @param int The index (base 1) of the matching node
|
|
* @param boolean True if the selection is to be performed recursively
|
|
*/
|
|
function filterByIndex($nodeName, $index, $deep) {
|
|
if (count($this->globalNodeContainer) != 0) {
|
|
foreach ($this->globalNodeContainer as $key =>$value) {
|
|
$currNode =& $this->globalNodeContainer[$key];
|
|
$this->_filterByIndex($currNode, $nodeName, $index, $deep);
|
|
}
|
|
}
|
|
} //filterByIndex
|
|
|
|
/**
|
|
* Selects named elements of the specified index
|
|
* @param object The context node
|
|
* @param string The pattern segment containing the node expression
|
|
* @param int The index (base 1) of the matching node
|
|
* @param boolean True if the selection is to be performed recursively
|
|
*/
|
|
function _filterByIndex(&$contextNode, $nodeName, $index, $deep) {
|
|
if (($contextNode->nodeType == DOMIT_ELEMENT_NODE) ||
|
|
($contextNode->nodeType == DOMIT_DOCUMENT_NODE)) {
|
|
$total = $contextNode->childCount;
|
|
$nodeCounter = 0;
|
|
|
|
for ($i = 0; $i < $total; $i++) {
|
|
$currChildNode =& $contextNode->childNodes[$i];
|
|
|
|
if ($currChildNode->nodeName == $nodeName) {
|
|
$nodeCounter++;
|
|
|
|
if ($nodeCounter == $index) {
|
|
$this->localNodeContainer[] =& $currChildNode;
|
|
}
|
|
}
|
|
|
|
if ($deep) {
|
|
$this->_filterByIndex($currChildNode, $nodeName, $index, $deep);
|
|
}
|
|
}
|
|
}
|
|
} //_filterByIndex
|
|
|
|
/**
|
|
* Selects named elements with the specified named child
|
|
* @param string The pattern segment containing the node expression
|
|
* @param string The tag name of the matching child
|
|
* @param boolean True if the selection is to be performed recursively
|
|
*/
|
|
function filterByChildName($nodeName, $childName, $deep) {
|
|
if (count($this->globalNodeContainer) != 0) {
|
|
foreach ($this->globalNodeContainer as $key =>$value) {
|
|
$currNode =& $this->globalNodeContainer[$key];
|
|
$this->_filterByChildName($currNode, $nodeName, $childName, $deep);
|
|
}
|
|
}
|
|
} //filterByChildName
|
|
|
|
/**
|
|
* Selects named elements with the specified named child
|
|
* @param object The context node
|
|
* @param string The pattern segment containing the node expression
|
|
* @param string The tag name of the matching child
|
|
* @param boolean True if the selection is to be performed recursively
|
|
*/
|
|
function _filterByChildName(&$contextNode, $nodeName, $childName, $deep) {
|
|
if (($contextNode->nodeType == DOMIT_ELEMENT_NODE) ||
|
|
($contextNode->nodeType == DOMIT_DOCUMENT_NODE)) {
|
|
$total = $contextNode->childCount;
|
|
|
|
for ($i = 0; $i < $total; $i++) {
|
|
$currChildNode =& $contextNode->childNodes[$i];
|
|
|
|
if (($currChildNode->nodeName == $nodeName) &&
|
|
($currChildNode->nodeType == DOMIT_ELEMENT_NODE)) {
|
|
$total2 = $currChildNode->childCount;
|
|
|
|
for ($j = 0; $j < $total2; $j++) {
|
|
$currChildChildNode =& $currChildNode->childNodes[$j];
|
|
|
|
if ($currChildChildNode->nodeName == $childName) {
|
|
$this->localNodeContainer[] =& $currChildNode;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($deep) {
|
|
$this->_filterByChildName($currChildNode, $nodeName, $childName, $deep);
|
|
}
|
|
}
|
|
}
|
|
} //_filterByChildName
|
|
|
|
/**
|
|
* Selects named attributes of the current context nodes
|
|
* @param string The attribute name, or * to match all attributes
|
|
*/
|
|
function selectAttribute($attrName) {
|
|
if (count($this->globalNodeContainer) != 0) {
|
|
foreach ($this->globalNodeContainer as $key =>$value) {
|
|
$currNode =& $this->globalNodeContainer[$key];
|
|
|
|
$isRecursive = ($this->searchType == DOMIT_XPATH_SEARCH_VARIABLE) ? true : false;
|
|
$this->_selectAttribute($currNode, $attrName, $isRecursive);
|
|
}
|
|
}
|
|
|
|
$this->charContainer = '';
|
|
} //selectAttribute
|
|
|
|
/**
|
|
* Selects all attributes of the context nodes
|
|
* @param object The context node
|
|
* @param string The attribute name, or * to match all attributes
|
|
* @param boolean True if the selection is to be performed recursively
|
|
*/
|
|
function _selectAttribute(&$contextNode, $attrName, $deep) {
|
|
if (($contextNode->nodeType == DOMIT_ELEMENT_NODE) ||
|
|
($contextNode->nodeType == DOMIT_DOCUMENT_NODE)) {
|
|
$total = $contextNode->childCount;
|
|
|
|
for ($i = 0; $i < $total; $i++) {
|
|
$currNode =& $contextNode->childNodes[$i];
|
|
|
|
if ($currNode->nodeType == DOMIT_ELEMENT_NODE) {
|
|
if ($attrName == '*') {
|
|
$total2 = $currNode->attributes->getLength();
|
|
|
|
for ($j = 0; $j < $total2; $j++) {
|
|
$this->localNodeContainer[] =& $currNode->attributes->item($j);
|
|
}
|
|
}
|
|
else {
|
|
if ($currNode->hasAttribute($attrName)) {
|
|
$this->localNodeContainer[] =& $currNode->getAttributeNode($attrName);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($deep) {
|
|
$this->_selectAttribute($currNode, $attrName, $deep);
|
|
}
|
|
}
|
|
}
|
|
} //_selectAttribute
|
|
|
|
|
|
/**
|
|
* Selects all child nodes of the current context nodes
|
|
* @param string The element name
|
|
*/
|
|
function selectNamedChild($tagName) {
|
|
if (count($this->globalNodeContainer) != 0) {
|
|
foreach ($this->globalNodeContainer as $key =>$value) {
|
|
$currNode =& $this->globalNodeContainer[$key];
|
|
|
|
$isRecursive = ($this->searchType == DOMIT_XPATH_SEARCH_VARIABLE) ? true : false;
|
|
$this->_selectNamedChild($currNode, $tagName, $isRecursive);
|
|
}
|
|
}
|
|
|
|
$this->charContainer = '';
|
|
} //selectNamedChild
|
|
|
|
/**
|
|
* Selects all child nodes of the context node
|
|
* @param object The context node
|
|
* @param string The element name
|
|
* @param boolean True if the selection is to be performed recursively
|
|
*/
|
|
function _selectNamedChild(&$contextNode, $tagName, $deep = false) {
|
|
if (($contextNode->nodeType == DOMIT_ELEMENT_NODE) ||
|
|
($contextNode->nodeType == DOMIT_DOCUMENT_NODE)) {
|
|
$total = $contextNode->childCount;
|
|
|
|
for ($i = 0; $i < $total; $i++) {
|
|
$currChildNode =& $contextNode->childNodes[$i];
|
|
|
|
if (($currChildNode->nodeType == DOMIT_ELEMENT_NODE) ||
|
|
($currChildNode->nodeType == DOMIT_DOCUMENT_NODE)) {
|
|
if (($tagName == '*') || ($tagName == $currChildNode->nodeName)) {
|
|
$this->localNodeContainer[] =& $currChildNode;
|
|
}
|
|
|
|
if ($deep) {
|
|
$this->_selectNamedChild($currChildNode, $tagName, $deep);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} //_selectNamedChild
|
|
|
|
/**
|
|
* Selects parent node of the current context nodes
|
|
*/
|
|
function selectParent() {
|
|
if (count($this->globalNodeContainer) != 0) {
|
|
foreach ($this->globalNodeContainer as $key =>$value) {
|
|
$currNode =& $this->globalNodeContainer[$key];
|
|
|
|
$isRecursive = ($this->searchType == DOMIT_XPATH_SEARCH_VARIABLE) ? true : false;
|
|
$this->_selectParent($currNode, $isRecursive);
|
|
}
|
|
}
|
|
|
|
$this->charContainer = '';
|
|
} //selectParent
|
|
|
|
/**
|
|
* Selects parent node of the current context nodes
|
|
* @param object The context node
|
|
* @param boolean True if the selection is to be performed recursively
|
|
*/
|
|
function _selectParent(&$contextNode, $deep = false) {
|
|
if ($contextNode->nodeType == DOMIT_ELEMENT_NODE) {
|
|
if ($contextNode->parentNode != null) {
|
|
$this->localNodeContainer[] =& $contextNode->parentNode;
|
|
}
|
|
}
|
|
|
|
if ($deep) {
|
|
if (($contextNode->nodeType == DOMIT_ELEMENT_NODE) ||
|
|
($contextNode->nodeType == DOMIT_DOCUMENT_NODE)) {
|
|
$total = $contextNode->childCount;
|
|
|
|
for ($i = 0; $i < $total; $i++) {
|
|
$currNode =& $contextNode->childNodes[$i];
|
|
|
|
if ($currNode->nodeType == DOMIT_ELEMENT_NODE) {
|
|
$this->_selectParent($contextNode, $deep);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} //_selectParent
|
|
|
|
/**
|
|
* Selects any nodes of the current context nodes which match the given function
|
|
*/
|
|
function selectNodesByFunction() {
|
|
$doProcess = false;
|
|
$targetNodeType = -1;
|
|
|
|
switch (strtolower(trim($this->charContainer))) {
|
|
case 'last()':
|
|
if (count($this->globalNodeContainer) != 0) {
|
|
foreach ($this->globalNodeContainer as $key =>$value) {
|
|
$currNode =& $this->globalNodeContainer[$key];
|
|
|
|
if ($currNode->nodeType == DOMIT_ELEMENT_NODE) {
|
|
if ($currNode->lastChild != null) {
|
|
$this->localNodeContainer[] =& $currNode->lastChild;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'text()':
|
|
$doProcess = true;
|
|
$targetNodeType = DOMIT_TEXT_NODE;
|
|
break;
|
|
|
|
case 'comment()':
|
|
$doProcess = true;
|
|
$targetNodeType = DOMIT_COMMENT_NODE;
|
|
break;
|
|
|
|
case 'processing-instruction()':
|
|
$doProcess = true;
|
|
$targetNodeType = DOMIT_PROCESSING_INSTRUCTION_NODE;
|
|
break;
|
|
}
|
|
|
|
if ($doProcess) {
|
|
if (count($this->globalNodeContainer) != 0) {
|
|
foreach ($this->globalNodeContainer as $key =>$value) {
|
|
$currNode =& $this->globalNodeContainer[$key];
|
|
|
|
if ($currNode->nodeType == DOMIT_ELEMENT_NODE) {
|
|
$total = $currNode->childCount;
|
|
|
|
for ($j = 0; $j < $total; $j++) {
|
|
if ($currNode->childNodes[$j]->nodeType == $targetNodeType) {
|
|
$this->localNodeContainer[] =& $currNode->childNodes[$j];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$this->charContainer = '';
|
|
} //selectNodesByFunction
|
|
|
|
/**
|
|
* Splits the supplied pattern into searchable segments
|
|
* @param string The pattern
|
|
*/
|
|
function splitPattern($pattern) {
|
|
//split multiple patterns if they exist (e.g. pattern1 | pattern2 | pattern3)
|
|
$this->arPathSegments =& explode(DOMIT_XPATH_SEPARATOR_OR, $pattern);
|
|
|
|
//split each pattern by relative path dividers (i.e., '//')
|
|
$total = count($this->arPathSegments);
|
|
|
|
for ($i = 0; $i < $total; $i++) {
|
|
$this->arPathSegments[$i] =& explode(DOMIT_XPATH_SEPARATOR_RELATIVE, trim($this->arPathSegments[$i]));
|
|
|
|
$currArray =& $this->arPathSegments[$i];
|
|
$total2 = count($currArray);
|
|
|
|
for ($j = 0; $j < $total2; $j++) {
|
|
$currArray[$j] =& explode(DOMIT_XPATH_SEPARATOR_ABSOLUTE, $currArray[$j]);
|
|
}
|
|
}
|
|
} //splitPattern
|
|
|
|
/**
|
|
* Converts long XPath syntax into abbreviated XPath syntax
|
|
* @param string The pattern
|
|
* @return string The normalized pattern
|
|
*/
|
|
function normalize($pattern) {
|
|
$pattern = strtr($pattern, $this->normalizationTable);
|
|
|
|
while (strpos($pattern, ' ') !== false) {
|
|
$pattern = str_replace(' ', ' ', $pattern);
|
|
}
|
|
|
|
$pattern = strtr($pattern, $this->normalizationTable2);
|
|
$pattern = strtr($pattern, $this->normalizationTable3);
|
|
|
|
return $pattern;
|
|
} //normalize
|
|
|
|
/**
|
|
* Initializes the contextNode and searchType
|
|
* @param array The current array of path segments
|
|
* @return int The index of the first array item to begin the search at
|
|
*/
|
|
function initSearch(&$currArPathSegments) {
|
|
$this->globalNodeContainer = array();
|
|
|
|
if (is_null($currArPathSegments[0])) {
|
|
if (count($currArPathSegments) == 1) {
|
|
//variable path
|
|
$this->searchType = DOMIT_XPATH_SEARCH_VARIABLE;
|
|
$this->globalNodeContainer[] =& $this->callingNode->ownerDocument;
|
|
}
|
|
else {
|
|
//absolute path
|
|
$this->searchType = DOMIT_XPATH_SEARCH_ABSOLUTE;
|
|
$this->globalNodeContainer[] =& $this->callingNode->ownerDocument;
|
|
}
|
|
}
|
|
else {
|
|
//relative path
|
|
$this->searchType = DOMIT_XPATH_SEARCH_RELATIVE;
|
|
|
|
if ($this->callingNode->uid != $this->callingNode->ownerDocument->uid) {
|
|
$this->globalNodeContainer[] =& $this->callingNode;
|
|
}
|
|
else {
|
|
$this->globalNodeContainer[] =& $this->callingNode->ownerDocument;
|
|
}
|
|
}
|
|
} //initSearch
|
|
} //DOMIT_XPath
|
|
?>
|