📄 xpath.class.php
字号:
* 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++; $pre = '<pre STYLE="border:solid thin '. $color[$colIndex % 6] . '; padding:5">'; $out = '<div align="left"> ' . $pre . "<STRONG>{$fileName} : {$functionName}</STRONG>"; echo $out; echo '<a style="float:right" name="'.$this->iDebugNextLinkNumber.'Open" href="#'.$this->iDebugNextLinkNumber.'Close">Function Close '.$this->iDebugNextLinkNumber.'</a>'; 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>"; 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"); $iOpenLinkNumber = array_pop($this->aDebugOpenLinks); echo '<a style="float:right" name="'.$iOpenLinkNumber.'Close" href="#'.$iOpenLinkNumber.'Open">Function Open '.$iOpenLinkNumber.'</a>'; 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. * * if $param is not given, all properties will be returned in a hash. * * @param $param (string) the property you want the value of, or NULL for all the properties * @return (mixed) string OR hash of all params, or NULL on an unknown parameter. */ function getProperties($param=NULL) { $this->properties['hasContent'] = !empty($this->nodeRoot); $this->properties['caseFolding'] = $this->parseOptions[XML_OPTION_CASE_FOLDING]; $this->properties['skipWhiteSpaces'] = $this->parseOptions[XML_OPTION_SKIP_WHITE]; if (empty($param)) return $this->properties; if (isSet($this->properties[$param])) { return $this->properties[$param]; } else { return NULL; } } /** * Set an xml_parser_set_option() * * @param $optionID (int) The option ID (e.g. XML_OPTION_SKIP_WHITE) * @param $value (int) The option value. * @see XML parser functions in PHP doc */ function setXmlOption($optionID, $value) { if (!is_numeric($optionID)) return; $this->parseOptions[$optionID] = $value; } /** * Sets a number of xml_parser_set_option()s * * @param $userXmlOptions (array) An array of parser options. * @see setXmlOption */ function setXmlOptions($userXmlOptions=array()) { if (!is_array($userXmlOptions)) return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -