📄 xpath.class.php
字号:
$hilightIsActive = is_array($hilightXpathList); if ($hilightIsActive) { $this->indentStep = ' '; } // Cache this now $this->parseSkipWhiteCache = isSet($this->parseOptions[XML_OPTION_SKIP_WHITE]) ? $this->parseOptions[XML_OPTION_SKIP_WHITE] : FALSE; /////////////////////////////////////// // Get the starting node and begin with the header // Get the start node. The super root is a special case. $startNode = NULL; if (empty($absoluteXPath)) { $superRoot = $this->nodeIndex['']; // If they didn't specify an xml header, use the one in the object if (is_null($xmlHeader)) { $xmlHeader = $this->parseSkipWhiteCache ? trim($superRoot['textParts'][0]) : $superRoot['textParts'][0]; // If we still don't have an XML header, then use a suitable default if (empty($xmlHeader)) { $xmlHeader = '<?xml version="1.0"?>'; } } if (isSet($superRoot['childNodes'][0])) $startNode = $superRoot['childNodes'][0]; } else { $startNode = $this->nodeIndex[$absoluteXPath]; } if (!empty($xmlHeader)) { $xmlOut = $this->parseSkipWhiteCache ? $xmlHeader."\n" : $xmlHeader; } else { $xmlOut = ''; } /////////////////////////////////////// // Output the document. if (($xmlOut .= $this->_InternalExport($startNode)) === FALSE) { return FALSE; } /////////////////////////////////////// // Convert our markers to hi-lights. if ($hilightIsActive) { $from = array('<', '>', chr(2), chr(3)); $to = array('<', '>', '<font color="#FF0000"><b>', '</b></font>'); $xmlOut = str_replace($from, $to, $xmlOut); } return $xmlOut; } /** * Export the xml document starting at the named node. * * @param $node (node) The node we have to start exporting from * @return (string) The string representation of the node. */ function _InternalExport($node) { $bDebugThisFunction = FALSE; if ($bDebugThisFunction) { $aStartTime = $this->_beginDebugFunction("_InternalExport"); echo "Exporting node: ".$node['xpath']."<br>\n"; } //////////////////////////////// // Quick out. if (empty($node)) return ''; // The output starts as empty. $xmlOut = ''; // This loop will output the text before the current child of a parent then the // current child. Where the child is a short tag we output the child, then move // onto the next child. Where the child is not a short tag, we output the open tag, // then queue up on currentParentStack[] the child. // // When we run out of children, we then output the last text part, and close the // 'parent' tag before popping the stack and carrying on. // // To illustrate, the numbers in this xml file indicate what is output on each // pass of the while loop: // // 1 // <1>2 // <2>3 // <3/>4 // </4>5 // <5/>6 // </6> // Although this is neater done using recursion, there's a 33% performance saving // to be gained by using this stack mechanism. // Only add CR's if "skip white spaces" was set. Otherwise leave as is. $CR = ($this->parseSkipWhiteCache) ? "\n" : ''; $currentIndent = ''; $hilightIsActive = is_array($this->hilightXpathList); // To keep track of where we are in the document we use a node stack. The node // stack has the following parallel entries: // 'Parent' => (array) A copy of the parent node that who's children we are // exporting // 'ChildIndex' => (array) The child index of the corresponding parent that we // are currently exporting. // 'Highlighted'=> (bool) If we are highlighting this node. Only relevant if // the hilight is active. // Setup our node stack. The loop is designed to output children of a parent, // not the parent itself, so we must put the parent on as the starting point. $nodeStack['Parent'] = array($node['parentNode']); // And add the childpos of our node in it's parent to our "child index stack". $nodeStack['ChildIndex'] = array($node['pos']); // We start at 0. $nodeStackIndex = 0; // We have not to output text before/after our node, so blank it. We will recover it // later $OldPreceedingStringValue = $nodeStack['Parent'][0]['textParts'][$node['pos']]; $OldPreceedingStringRef =& $nodeStack['Parent'][0]['textParts'][$node['pos']]; $OldPreceedingStringRef = ""; $currentXpath = ""; // While we still have data on our stack while ($nodeStackIndex >= 0) { // Count the children and get a copy of the current child. $iChildCount = count($nodeStack['Parent'][$nodeStackIndex]['childNodes']); $currentChild = $nodeStack['ChildIndex'][$nodeStackIndex]; // Only do the auto indenting if the $parseSkipWhiteCache flag was set. if ($this->parseSkipWhiteCache) $currentIndent = str_repeat($this->indentStep, $nodeStackIndex); if ($bDebugThisFunction) echo "Exporting child ".($currentChild+1)." of node {$nodeStack['Parent'][$nodeStackIndex]['xpath']}\n"; /////////////////////////////////////////// // Add the text before our child. // Add the text part before the current child $tmpTxt =& $nodeStack['Parent'][$nodeStackIndex]['textParts'][$currentChild]; if (isSet($tmpTxt) AND ($tmpTxt!="")) { // Only add CR indent if there were children if ($iChildCount) $xmlOut .= $CR.$currentIndent; // Hilight if necessary. $highlightStart = $highlightEnd = ''; if ($hilightIsActive) { $currentXpath = $nodeStack['Parent'][$nodeStackIndex]['xpath'].'/text()['.($currentChild+1).']'; if (in_array($currentXpath, $this->hilightXpathList)) { // Yes we hilight $highlightStart = chr(2); $highlightEnd = chr(3); } } $xmlOut .= $highlightStart.$nodeStack['Parent'][$nodeStackIndex]['textParts'][$currentChild].$highlightEnd; } if ($iChildCount && $nodeStackIndex) $xmlOut .= $CR; /////////////////////////////////////////// // Are there any more children? if ($iChildCount <= $currentChild) { // Nope, so output the last text before the closing tag $tmpTxt =& $nodeStack['Parent'][$nodeStackIndex]['textParts'][$currentChild+1]; if (isSet($tmpTxt) AND ($tmpTxt!="")) { // Hilight if necessary. $highlightStart = $highlightEnd = ''; if ($hilightIsActive) { $currentXpath = $nodeStack['Parent'][$nodeStackIndex]['xpath'].'/text()['.($currentChild+2).']'; if (in_array($currentXpath, $this->hilightXpathList)) { // Yes we hilight $highlightStart = chr(2); $highlightEnd = chr(3); } } $xmlOut .= $highlightStart .$currentIndent.$nodeStack['Parent'][$nodeStackIndex]['textParts'][$currentChild+1].$CR .$highlightEnd; } // Now close this tag, as we are finished with this child. // Potentially output an (slightly smaller indent). if ($this->parseSkipWhiteCache && count($nodeStack['Parent'][$nodeStackIndex]['childNodes'])) { $xmlOut .= str_repeat($this->indentStep, $nodeStackIndex - 1); } // Check whether the xml-tag is to be hilighted. $highlightStart = $highlightEnd = ''; if ($hilightIsActive) { $currentXpath = $nodeStack['Parent'][$nodeStackIndex]['xpath']; if (in_array($currentXpath, $this->hilightXpathList)) { // Yes we hilight $highlightStart = chr(2); $highlightEnd = chr(3); } } $xmlOut .= $highlightStart .'</'.$nodeStack['Parent'][$nodeStackIndex]['name'].'>' .$highlightEnd; // Decrement the $nodeStackIndex to go back to the next unfinished parent. $nodeStackIndex--; // If the index is 0 we are finished exporting the last node, as we may have been // exporting an internal node. if ($nodeStackIndex == 0) break; // Indicate to the parent that we are finished with this child. $nodeStack['ChildIndex'][$nodeStackIndex]++; continue; } /////////////////////////////////////////// // Ok, there are children still to process. // Queue up the next child (I can copy because I won't modify and copying is faster.) $nodeStack['Parent'][$nodeStackIndex + 1] = $nodeStack['Parent'][$nodeStackIndex]['childNodes'][$currentChild]; // Work out if it is a short child tag. $iGrandChildCount = count($nodeStack['Parent'][$nodeStackIndex + 1]['childNodes']); $shortGrandChild = (($iGrandChildCount == 0) AND (implode('',$nodeStack['Parent'][$nodeStackIndex + 1]['textParts'])=='')); /////////////////////////////////////////// // Assemble the attribute string first. $attrStr = ''; foreach($nodeStack['Parent'][$nodeStackIndex + 1]['attributes'] as $key=>$val) { // Should we hilight the attribute? if ($hilightIsActive AND in_array($currentXpath.'/attribute::'.$key, $this->hilightXpathList)) { $hiAttrStart = chr(2); $hiAttrEnd = chr(3); } else { $hiAttrStart = $hiAttrEnd = ''; } $attrStr .= ' '.$hiAttrStart.$key.'="'.$val.'"'.$hiAttrEnd; } /////////////////////////////////////////// // Work out what goes before and after the tag content $beforeTagContent = $currentIndent; if ($shortGrandChild) $afterTagContent = '/>'; else $afterTagContent = '>'; // Check whether the xml-tag is to be hilighted. if ($hilightIsActive) { $currentXpath = $nodeStack['Parent'][$nodeStackIndex + 1]['xpath']; if (in_array($currentXpath, $this->hilightXpathList)) { // Yes we hilight $beforeTagContent .= chr(2); $afterTagContent .= chr(3); } } $beforeTagContent .= '<';// if ($shortGrandChild) $afterTagContent .= $CR; /////////////////////////////////////////// // Output the tag $xmlOut .= $beforeTagContent .$nodeStack['Parent'][$nodeStackIndex + 1]['name'].$attrStr .$afterTagContent; /////////////////////////////////////////// // Carry on. // If it is a short tag, then we've already done this child, we just move to the next if ($shortGrandChild) { // Move to the next child, we need not go deeper in the tree. $nodeStack['ChildIndex'][$nodeStackIndex]++; // But if we are just exporting the one node we'd go no further. if ($nodeStackIndex == 0) break; } else { // Else queue up the child going one deeper in the stack $nodeStackIndex++; // Start with it's first child $nodeStack['ChildIndex'][$nodeStackIndex] = 0; } } $result = $xmlOut; // Repair what we "undid" $OldPreceedingStringRef = $OldPreceedingStringValue; //////////////////////////////////////////// if ($bDebugThisFunction) { $this->_closeDebugFunction($aStartTime, $result); } return $result; } //----------------------------------------------------------------------------------------- // XPathEngine ------ Import the XML
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -