⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xpath.class.inc

📁 groupoffice
💻 INC
📖 第 1 页 / 共 5 页
字号:
      $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.
    clearstatcache();
    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 = '  ';
    $hilightIsActive = is_array($hilightXpathList);
    if ($hilightIsActive) {
      $this->indentStep = '&nbsp;&nbsp;&nbsp;&nbsp;';
    }    
    
    // 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('&lt;', '&gt;', '<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 t

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -