📄 xpath.class.php
字号:
foreach($userXmlOptions as $key => $val) { $this->setXmlOption($key, $val); } } /** * Alternative way to control whether case-folding is enabled for this XML parser. * * Short cut to setXmlOptions(XML_OPTION_CASE_FOLDING, TRUE/FALSE) * * When it comes to XML, case-folding simply means uppercasing all tag- * and attribute-names (NOT the content) if set to TRUE. Note if you * have this option set, then your XPath queries will also be case folded * for you. * * @param $onOff (bool) (default TRUE) * @see XML parser functions in PHP doc */ function setCaseFolding($onOff=TRUE) { $this->parseOptions[XML_OPTION_CASE_FOLDING] = $onOff; } /** * Alternative way to control whether skip-white-spaces is enabled for this XML parser. * * Short cut to setXmlOptions(XML_OPTION_SKIP_WHITE, TRUE/FALSE) * * When it comes to XML, skip-white-spaces will trim the tag content. * An XML file with no whitespace will be faster to process, but will make * your data less human readable when you come to write it out. * * Running with this option on will slow the class down, so if you want to * speed up your XML, then run it through once skipping white-spaces, then * write out the new version of your XML without whitespace, then use the * new XML file with skip whitespaces turned off. * * @param $onOff (bool) (default TRUE) * @see XML parser functions in PHP doc */ function setSkipWhiteSpaces($onOff=TRUE) { $this->parseOptions[XML_OPTION_SKIP_WHITE] = $onOff; } /** * Get the node defined by the $absoluteXPath. * * @param $absoluteXPath (string) (optional, default is 'super-root') xpath to the node. * @return (array) The node, or FALSE if the node wasn't found. */ function &getNode($absoluteXPath='') { if ($absoluteXPath==='/') $absoluteXPath = ''; if (!isSet($this->nodeIndex[$absoluteXPath])) return FALSE; if ($this->_indexIsDirty) $this->reindexNodeTree(); return $this->nodeIndex[$absoluteXPath]; } /** * Get a the content of a node text part or node attribute. * * If the absolute Xpath references an attribute (Xpath ends with @ or attribute::), * then the text value of that node-attribute is returned. * Otherwise the Xpath is referencing a text part of the node. This can be either a * direct reference to a text part (Xpath ends with text()[<nr>]) or indirect reference * (a simple abs. Xpath to a node). * 1) Direct Reference (xpath ends with text()[<part-number>]): * If the 'part-number' is omitted, the first text-part is assumed; starting by 1. * Negative numbers are allowed, where -1 is the last text-part a.s.o. * 2) Indirect Reference (a simple abs. Xpath to a node): * Default is to return the *whole text*; that is the concated text-parts of the matching * node. (NOTE that only in this case you'll only get a copy and changes to the returned * value wounld have no effect). Optionally you may pass a parameter * $textPartNr to define the text-part you want; starting by 1. * Negative numbers are allowed, where -1 is the last text-part a.s.o. * * NOTE I : The returned value can be fetched by reference * E.g. $text =& wholeText(). If you wish to modify the text. * NOTE II: text-part numbers out of range will return FALSE * SIDENOTE:The function name is a suggestion from W3C in the XPath specification level 3. * * @param $absoluteXPath (string) xpath to the node (See above). * @param $textPartNr (int) If referring to a node, specifies which text part * to query. * @return (&string) A *reference* to the text if the node that the other * parameters describe or FALSE if the node is not found. */ function &wholeText($absoluteXPath, $textPartNr=NULL) { $status = FALSE; $text = NULL; if ($this->_indexIsDirty) $this->reindexNodeTree(); do { // try-block if (preg_match(";(.*)/(attribute::|@)([^/]*)$;U", $absoluteXPath, $matches)) { $absoluteXPath = $matches[1]; $attribute = $matches[3]; if (!isSet($this->nodeIndex[$absoluteXPath]['attributes'][$attribute])) { $this->_displayError("The $absoluteXPath/attribute::$attribute value isn't a node in this document.", __LINE__, __FILE__, FALSE); break; // try-block } $text =& $this->nodeIndex[$absoluteXPath]['attributes'][$attribute]; $status = TRUE; break; // try-block } // Xpath contains a 'text()'-function, thus goes right to a text node. If so interpete the Xpath. if (preg_match(":(.*)/text\(\)(\[(.*)\])?$:U", $absoluteXPath, $matches)) { $absoluteXPath = $matches[1]; if (!isSet($this->nodeIndex[$absoluteXPath])) { $this->_displayError("The $absoluteXPath value isn't a node in this document.", __LINE__, __FILE__, FALSE); break; // try-block } // Get the amount of the text parts in the node. $textPartSize = sizeOf($this->nodeIndex[$absoluteXPath]['textParts']); // default to the first text node if a text node was not specified $textPartNr = isSet($matches[2]) ? substr($matches[2],1,-1) : 1; // Support negative indexes like -1 === last a.s.o. if ($textPartNr < 0) $textPartNr = $textPartSize + $textPartNr +1; if (($textPartNr <= 0) OR ($textPartNr > $textPartSize)) { $this->_displayError("The $absoluteXPath/text()[$textPartNr] value isn't a NODE in this document.", __LINE__, __FILE__, FALSE); break; // try-block } $text =& $this->nodeIndex[$absoluteXPath]['textParts'][$textPartNr - 1]; $status = TRUE; break; // try-block } // At this point we have been given an xpath with neither a 'text()' nor 'attribute::' axis at the end // So we assume a get to text is wanted and use the optioanl fallback parameters $textPartNr if (!isSet($this->nodeIndex[$absoluteXPath])) { $this->_displayError("The $absoluteXPath value isn't a node in this document.", __LINE__, __FILE__, FALSE); break; // try-block } // Get the amount of the text parts in the node. $textPartSize = sizeOf($this->nodeIndex[$absoluteXPath]['textParts']); // If $textPartNr == NULL we return a *copy* of the whole concated text-parts if (is_null($textPartNr)) { unset($text); $text = implode('', $this->nodeIndex[$absoluteXPath]['textParts']); $status = TRUE; break; // try-block } // Support negative indexes like -1 === last a.s.o. if ($textPartNr < 0) $textPartNr = $textPartSize + $textPartNr +1; if (($textPartNr <= 0) OR ($textPartNr > $textPartSize)) { $this->_displayError("The $absoluteXPath has no text part at pos [$textPartNr] (Note: text parts start with 1).", __LINE__, __FILE__, FALSE); break; // try-block } $text =& $this->nodeIndex[$absoluteXPath]['textParts'][$textPartNr -1]; $status = TRUE; } while (FALSE); // END try-block if (!$status) return FALSE; return $text; } //----------------------------------------------------------------------------------------- // XPathEngine ------ Export the XML Document ------ //----------------------------------------------------------------------------------------- /** * Returns the containing XML as marked up HTML with specified nodes hi-lighted * * @param $absoluteXPath (string) The address of the node you would like to export. * If empty the whole document will be exported. * @param $hilighXpathList (array) A list of nodes that you would like to highlight * @return (mixed) The Xml document marked up as HTML so that it can * be viewed in a browser, including any XML headers. * FALSE on error. * @see _export() */ function exportAsHtml($absoluteXPath='', $hilightXpathList=array()) { $htmlString = $this->_export($absoluteXPath, $xmlHeader=NULL, $hilightXpathList); if (!$htmlString) return FALSE; return "<pre>\n" . $htmlString . "\n</pre>"; } /** * Given a context this function returns the containing XML * * @param $absoluteXPath (string) The address of the node you would like to export. * If empty the whole document will be exported. * @param $xmlHeader (array) The string that you would like to appear before * the XML content. ie before the <root></root>. If you * do not specify this argument, the xmlHeader that was * found in the parsed xml file will be used instead. * @return (mixed) The Xml fragment/document, suitable for writing * out to an .xml file or as part of a larger xml file, or * FALSE on error. * @see _export() */ function exportAsXml($absoluteXPath='', $xmlHeader=NULL) { $this->hilightXpathList = NULL; return $this->_export($absoluteXPath, $xmlHeader); } /** * Generates a XML string with the content of the current document and writes it to a file. * * Per default includes a <?xml ...> tag at the start of the data too. * * @param $fileName (string) * @param $absoluteXPath (string) The path to the parent node you want(see text above) * @param $xmlHeader (array) The string that you would like to appear before * the XML content. ie before the <root></root>. If you * do not specify this argument, the xmlHeader that was * found in the parsed xml file will be used instead. * @return (string) The returned string contains well-formed XML data * or FALSE on error. * @see exportAsXml(), exportAsHtml() */ function exportToFile($fileName, $absoluteXPath='', $xmlHeader=NULL) { $status = FALSE; do { // try-block if (!($hFile = fopen($fileName, "wb"))) { // Did we open the file ok? $errStr = "Failed to open the $fileName xml file."; break; // try-block } if ($this->properties['OS_supports_flock']) { if (!flock($hFile, LOCK_EX + LOCK_NB)) { // Lock the file $errStr = "Couldn't get an exclusive lock on the $fileName file."; break; // try-block } } if (!($xmlOut = $this->_export($absoluteXPath, $xmlHeader))) { $errStr = "Export failed"; break; // try-block } $iBytesWritten = fwrite($hFile, $xmlOut); if ($iBytesWritten != strlen($xmlOut)) { $errStr = "Write error when writing back the $fileName file."; break; // try-block } // Flush and unlock the file @fflush($hFile); $status = TRUE; } while(FALSE); @flock($hFile, LOCK_UN); @fclose($hFile); // Sanity check the produced file. if (filesize($fileName) < strlen($xmlOut)) { $errStr = "Write error when writing back the $fileName file."; $status = FALSE; } if (!$status) $this->_displayError($errStr, __LINE__, __FILE__, FALSE); return $status; } /** * Generates a XML string with the content of the current document. * * This is the start for extracting the XML-data from the node-tree. We do some preperations * and then call _InternalExport() to fetch the main XML-data. You optionally may pass * xpath to any node that will then be used as top node, to extract XML-parts of the * document. Default is '', meaning to extract the whole document. * * You also may pass a 'xmlHeader' (usually something like <?xml version="1.0"? > that will * overwrite any other 'xmlHeader', if there was one in the original source. If there * wasn't one in the original source, and you still don't specify one, then it will * use a default of <?xml version="1.0"? > * Finaly, when exporting to HTML, you may pass a vector xPaths you want to hi-light. * The hi-lighted tags and attributes will receive a nice color. * * NOTE I : The output can have 2 formats: * a) If "skip white spaces" is/was set. (Not Recommended - slower) * The output is formatted by adding indenting and carriage returns. * b) If "skip white spaces" is/was *NOT* set. * 'as is'. No formatting is done. The output should the same as the * the original parsed XML source. * * @param $absoluteXPath (string) (optional, default is root) The node we choose as top-node * @param $xmlHeader (string) (optional) content before <root/> (see text above) * @param $hilightXpath (array) (optional) a vector of xPaths to nodes we wat to * hi-light (see text above) * @return (mixed) The xml string, or FALSE on error. */ function _export($absoluteXPath='', $xmlHeader=NULL, $hilightXpathList='') { // Check whether a root node is given. if (empty($absoluteXpath)) $absoluteXpath = ''; if ($absoluteXpath == '/') $absoluteXpath = ''; if ($this->_indexIsDirty) $this->reindexNodeTree(); if (!isSet($this->nodeIndex[$absoluteXpath])) { // If the $absoluteXpath was '' and it didn't exist, then the document is empty // and we can safely return ''. if ($absoluteXpath == '') return ''; $this->_displayError("The given xpath '{$absoluteXpath}' isn't a node in this document.", __LINE__, __FILE__, FALSE); return FALSE; } $this->hilightXpathList = $hilightXpathList; $this->indentStep = ' ';
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -