📄 xpath.class.inc
字号:
* ### Terminate should not be allowed --fab. Should it?? N.S.
*
* @param $message (string) Error message to be displayed.
* @param $lineNumber (int) line number given by __LINE__
* @param $terminate (bool) (default TURE) End the execution of this script.
*/
function _displayError($message, $lineNumber='-', $file='-', $terminate=TRUE) {
// Display the error message.
$err = '<b>XPath error in '.basename($file).':'.$lineNumber.'</b> '.$message."<br \>\n";
$this->_setLastError($message, $lineNumber, $file);
if (($this->properties['verboseLevel'] > 0) OR ($terminate)) echo $err;
// End the execution of this script.
if ($terminate) exit;
}
/**
* Displays a diagnostic message
*
* This method displays an error messages
*
* @param $message (string) Error message to be displayed.
* @param $lineNumber (int) line number given by __LINE__
*/
function _displayMessage($message, $lineNumber='-', $file='-') {
// Display the error message.
$err = '<b>XPath message from '.basename($file).':'.$lineNumber.'</b> '.$message."<br \>\n";
if ($this->properties['verboseLevel'] > 0) echo $err;
}
/**
* Called to begin the debug run of a function.
*
* This method starts a <DIV><PRE> tag so that the entry to this function
* is clear to the debugging user. Call _closeDebugFunction() at the
* end of the function to create a clean box round the function call.
*
* @author Nigel Swinson <nigelswinson@users.sourceforge.net>
* @author Sam Blum <bs_php@infeer.com>
* @param $functionName (string) the name of the function we are beginning to debug
* @return (array) the output from the microtime() function.
* @see _closeDebugFunction()
*/
function _beginDebugFunction($functionName) {
$fileName = basename(__FILE__);
static $color = array('green','blue','red','lime','fuchsia', 'aqua');
static $colIndex = -1;
$colIndex++;
echo '<div style="clear:both" align="left"> ';
echo '<pre STYLE="border:solid thin '. $color[$colIndex % 6] . '; padding:5">';
echo '<a style="float:right;margin:5px" name="'.$this->iDebugNextLinkNumber.'Open" href="#'.$this->iDebugNextLinkNumber.'Close">Function Close '.$this->iDebugNextLinkNumber.'</a>';
echo "<STRONG>{$fileName} : {$functionName}</STRONG>";
echo '<hr style="clear:both">';
array_push($this->aDebugOpenLinks, $this->iDebugNextLinkNumber);
$this->iDebugNextLinkNumber++;
return microtime();
}
/**
* Called to end the debug run of a function.
*
* This method ends a <DIV><PRE> block and reports the time since $aStartTime
* is clear to the debugging user.
*
* @author Nigel Swinson <nigelswinson@users.sourceforge.net>
* @param $aStartTime (array) the time that the function call was started.
* @param $return_value (mixed) the return value from the function call that
* we are debugging
*/
function _closeDebugFunction($aStartTime, $returnValue = "") {
echo "<hr>";
$iOpenLinkNumber = array_pop($this->aDebugOpenLinks);
echo '<a style="float:right" name="'.$iOpenLinkNumber.'Close" href="#'.$iOpenLinkNumber.'Open">Function Open '.$iOpenLinkNumber.'</a>';
if (isSet($returnValue)) {
if (is_array($returnValue))
echo "Return Value: ".print_r($returnValue)."\n";
else if (is_numeric($returnValue))
echo "Return Value: ".(string)$returnValue."\n";
else if (is_bool($returnValue))
echo "Return Value: ".($returnValue ? "TRUE" : "FALSE")."\n";
else
echo "Return Value: \"".htmlspecialchars($returnValue)."\"\n";
}
$this->_profileFunction($aStartTime, "Function took");
echo '<br style="clear:both">';
echo " \n</pre></div>";
}
/**
* Call to return time since start of function for Profiling
*
* @param $aStartTime (array) the time that the function call was started.
* @param $alertString (string) the string to describe what has just finished happening
*/
function _profileFunction($aStartTime, $alertString) {
// Print the time it took to call this function.
$now = explode(' ', microtime());
$last = explode(' ', $aStartTime);
$delta = (round( (($now[1] - $last[1]) + ($now[0] - $last[0]))*1000 ));
echo "\n{$alertString} <strong>{$delta} ms</strong>";
}
/**
* Echo an XPath context for diagnostic purposes
*
* @param $context (array) An XPath context
*/
function _printContext($context) {
echo "{$context['nodePath']}({$context['pos']}/{$context['size']})";
}
/**
* This is a debug helper function. It dumps the node-tree as HTML
*
* *QUICK AND DIRTY*. Needs some polishing.
*
* @param $node (array) A node
* @param $indent (string) (optional, default=''). For internal recursive calls.
*/
function _treeDump($node, $indent = '') {
$out = '';
// Get rid of recursion
$parentName = empty($node['parentNode']) ? "SUPER ROOT" : $node['parentNode']['name'];
unset($node['parentNode']);
$node['parentNode'] = $parentName ;
$out .= "NODE[{$node['name']}]\n";
foreach($node as $key => $val) {
if ($key === 'childNodes') continue;
if (is_Array($val)) {
$out .= $indent . " [{$key}]\n" . arrayToStr($val, $indent . ' ');
} else {
$out .= $indent . " [{$key}] => '{$val}' \n";
}
}
if (!empty($node['childNodes'])) {
$out .= $indent . " ['childNodes'] (Size = ".sizeOf($node['childNodes']).")\n";
foreach($node['childNodes'] as $key => $childNode) {
$out .= $indent . " [$key] => " . $this->_treeDump($childNode, $indent . ' ') . "\n";
}
}
if (empty($indent)) {
return "<pre>" . htmlspecialchars($out) . "</pre>";
}
return $out;
}
} // END OF CLASS XPathBase
/************************************************************************************************
* ===============================================================================================
* X P a t h E n g i n e - Class
* ===============================================================================================
************************************************************************************************/
class XPathEngine extends XPathBase {
// List of supported XPath axes.
// What a stupid idea from W3C to take axes name containing a '-' (dash)
// NOTE: We replace the '-' with '_' to avoid the conflict with the minus operator.
// We will then do the same on the users Xpath querys
// -sibling => _sibling
// -or- => _or_
//
// This array contains a list of all valid axes that can be evaluated in an
// XPath query.
var $axes = array ( 'ancestor', 'ancestor_or_self', 'attribute', 'child', 'descendant',
'descendant_or_self', 'following', 'following_sibling',
'namespace', 'parent', 'preceding', 'preceding_sibling', 'self'
);
// List of supported XPath functions.
// What a stupid idea from W3C to take function name containing a '-' (dash)
// NOTE: We replace the '-' with '_' to avoid the conflict with the minus operator.
// We will then do the same on the users Xpath querys
// starts-with => starts_with
// substring-before => substring_before
// substring-after => substring_after
// string-length => string_length
//
// This array contains a list of all valid functions that can be evaluated
// in an XPath query.
var $functions = array ( 'last', 'position', 'count', 'id', 'name',
'string', 'concat', 'starts_with', 'contains', 'substring_before',
'substring_after', 'substring', 'string_length', 'normalize_space', 'translate',
'boolean', 'not', 'true', 'false', 'lang', 'number', 'sum', 'floor',
'ceiling', 'round', 'x_lower', 'x_upper', 'generate_id' );
// List of supported XPath operators.
//
// This array contains a list of all valid operators that can be evaluated
// in a predicate of an XPath query. The list is ordered by the
// precedence of the operators (lowest precedence first).
var $operators = array( ' or ', ' and ', '=', '!=', '<=', '<', '>=', '>',
'+', '-', '*', ' div ', ' mod ', ' | ');
// List of literals from the xPath string.
var $axPathLiterals = array();
// The index and tree that is created during the analysis of an XML source.
var $nodeIndex = array();
var $nodeRoot = array();
var $emptyNode = array(
'name' => '', // The tag name. E.g. In <FOO bar="aaa"/> it would be 'FOO'
'attributes' => array(), // The attributes of the tag E.g. In <FOO bar="aaa"/> it would be array('bar'=>'aaa')
'childNodes' => array(), // Array of pointers to child nodes.
'textParts' => array(), // Array of text parts between the cilderen E.g. <FOO>aa<A>bb<B/>cc</A>dd</FOO> -> array('aa','bb','cc','dd')
'parentNode' => NULL, // Pointer to parent node or NULL if this node is the 'super root'
//-- *!* Following vars are set by the indexer and is for optimisation only *!*
'depth' => 0, // The tag depth (or tree level) starting with the root tag at 0.
'pos' => 0, // Is the zero-based position this node has in the parents 'childNodes'-list.
'contextPos' => 1, // Is the one-based position this node has by counting the siblings tags (tags with same name)
'xpath' => '' // Is the abs. XPath to this node.
);
var $_indexIsDirty = FALSE;
// These variable used during the parse XML source
var $nodeStack = array(); // The elements that we have still to close.
var $parseStackIndex = 0; // The current element of the nodeStack[] that we are adding to while
// parsing an XML source. Corresponds to the depth of the xml node.
// in our input data.
var $parseOptions = array(); // Used to set the PHP's XML parser options (see xml_parser_set_option)
var $parsedTextLocation = ''; // A reference to where we have to put char data collected during XML parsing
var $parsInCData = 0 ; // Is >0 when we are inside a CDATA section.
var $parseSkipWhiteCache = 0; // A cache of the skip whitespace parse option to speed up the parse.
// This is the array of error strings, to keep consistency.
var $errorStrings = array(
'AbsoluteXPathRequired' => "The supplied xPath '%s' does not *uniquely* describe a node in the xml document.",
'NoNodeMatch' => "The supplied xPath-query '%s' does not match *any* node in the xml document.",
'RootNodeAlreadyExists' => "An xml document may have only one root node."
);
/**
* Constructor
*
* Optionally you may call this constructor with the XML-filename to parse and the
* XML option vector. Each of the entries in the option vector will be passed to
* xml_parser_set_option().
*
* A option vector sample:
* $xmlOpt = array(XML_OPTION_CASE_FOLDING => FALSE,
* XML_OPTION_SKIP_WHITE => TRUE);
*
* @param $userXmlOptions (array) (optional) Vector of (<optionID>=><value>,
* <optionID>=><value>, ...). See PHP's
* xml_parser_set_option() docu for a list of possible
* options.
* @see importFromFile(), importFromString(), setXmlOptions()
*/
function XPathEngine($userXmlOptions=array()) {
parent::XPathBase();
// Default to not folding case
$this->parseOptions[XML_OPTION_CASE_FOLDING] = FALSE;
// And not skipping whitespace
$this->parseOptions[XML_OPTION_SKIP_WHITE] = FALSE;
// Now merge in the overrides.
// Don't use PHP's array_merge!
if (is_array($userXmlOptions)) {
foreach($userXmlOptions as $key => $val) $this->parseOptions[$key] = $val;
}
}
/**
* Resets the object so it's able to take a new xml sting/file
*
* Constructing objects is slow. If you can, reuse ones that you have used already
* by using this reset() function.
*/
function reset() {
parent::reset();
$this->properties['xmlFile'] = '';
$this->parseStackIndex = 0;
$this->parsedTextLocation = '';
$this->parsInCData = 0;
$this->nodeIndex = array();
$this->nodeRoot = array();
$this->nodeStack = array();
$this->aLiterals = array();
$this->_indexIsDirty = FALSE;
}
//-----------------------------------------------------------------------------------------
// XPathEngine ------ Get / Set Stuff ------
//-----------------------------------------------------------------------------------------
/**
* Returns the property/ies you want.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -