Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/backup/util/xml/parser/processors/simplified_parser_processor.class.php
Go to the documentation of this file.
00001 <?php
00002 
00003 // This file is part of Moodle - http://moodle.org/
00004 //
00005 // Moodle is free software: you can redistribute it and/or modify
00006 // it under the terms of the GNU General Public License as published by
00007 // the Free Software Foundation, either version 3 of the License, or
00008 // (at your option) any later version.
00009 //
00010 // Moodle is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License
00016 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
00017 
00025 require_once($CFG->dirroot.'/backup/util/xml/parser/processors/progressive_parser_processor.class.php');
00026 
00040 abstract class simplified_parser_processor extends progressive_parser_processor {
00041     protected $paths;       // array of paths we are interested on
00042     protected $parentpaths; // array of parent paths of the $paths
00043     protected $parentsinfo; // array of parent attributes to be added as child tags
00044     protected $startendinfo;// array (stack) of startend information
00045 
00046     public function __construct(array $paths = array()) {
00047         parent::__construct();
00048         $this->paths = array();
00049         $this->parentpaths = array();
00050         $this->parentsinfo = array();
00051         $this->startendinfo = array();
00052         // Add paths and parentpaths. We are looking for attributes there
00053         foreach ($paths as $key => $path) {
00054             $this->add_path($path);
00055         }
00056     }
00057 
00058     public function add_path($path) {
00059         $this->paths[] = $path;
00060         $this->parentpaths[] = progressive_parser::dirname($path);
00061     }
00062 
00066     abstract protected function dispatch_chunk($data);
00067 
00071     abstract protected function notify_path_start($path);
00072 
00076     abstract protected function notify_path_end($path);
00077 
00083     public function process_chunk($data) {
00084         // Precalculate some vars for readability
00085         $path = $data['path'];
00086         $parentpath = progressive_parser::dirname($path);
00087         $tag = basename($path);
00088 
00089         // If the path is a registered parent one, store all its tags
00090         // so, we'll be able to find attributes later when processing
00091         // (child) registered paths (to get attributes if present)
00092         if ($this->path_is_selected_parent($path)) { // if path is parent
00093             if (isset($data['tags'])) {              // and has tags, save them
00094                 $this->parentsinfo[$path] = $data['tags'];
00095             }
00096         }
00097 
00098         // If the path is a registered one, let's process it
00099         if ($this->path_is_selected($path)) {
00100 
00101             // Send all the pending notify_path_start/end() notifications
00102             $this->process_pending_startend_notifications($path, 'start');
00103 
00104             // First of all, look for attributes available at parentsinfo
00105             // in order to get them available as normal tags
00106             if (isset($this->parentsinfo[$parentpath][$tag]['attrs'])) {
00107                 $data['tags'] = array_merge($this->parentsinfo[$parentpath][$tag]['attrs'], $data['tags']);
00108                 unset($this->parentsinfo[$parentpath][$tag]['attrs']);
00109             }
00110             // Now, let's simplify the tags array, ignoring tag attributtes and
00111             // reconverting to simpler name => value array. At the same time,
00112             // check for all the tag values being whitespace-string values, if all them
00113             // are whitespace strings, we aren't going to postprocess/dispatch the chunk
00114             $alltagswhitespace = true;
00115             foreach ($data['tags'] as $key => $value) {
00116                 // If the value is already a single value, do nothing
00117                 // surely was added above from parentsinfo attributes,
00118                 // so we'll process the chunk always
00119                 if (!is_array($value)) {
00120                     $alltagswhitespace = false;
00121                     continue;
00122                 }
00123 
00124                 // If the path including the tag name matches another selected path
00125                 // (registered or parent) and is null or begins with linefeed, we know it's part
00126                 // of another chunk, delete it, another chunk will contain that info
00127                 if ($this->path_is_selected($path . '/' . $key) ||
00128                     $this->path_is_selected_parent($path . '/' . $key)) {
00129                     if (!isset($value['cdata']) || substr($value['cdata'], 0, 1) === "\n") {
00130                         unset($data['tags'][$key]);
00131                         continue;
00132                     }
00133                 }
00134 
00135                 // Convert to simple name => value array
00136                 $data['tags'][$key] = isset($value['cdata']) ? $value['cdata'] : null;
00137 
00138                 // Check $alltagswhitespace continues being true
00139                 if ($alltagswhitespace && strlen($data['tags'][$key]) !== 0 && trim($data['tags'][$key]) !== '') {
00140                     $alltagswhitespace = false; // Found non-whitespace value
00141                 }
00142             }
00143 
00144             // Arrived here, if the chunk has tags and not all tags are whitespace,
00145             // send it to postprocess filter that will decide about dispatching. Else
00146             // skip the chunk completely
00147             if (!empty($data['tags']) && !$alltagswhitespace) {
00148                 return $this->postprocess_chunk($data);
00149             } else {
00150                 $this->chunks--; // Chunk skipped
00151             }
00152         } else {
00153             $this->chunks--; // Chunk skipped
00154         }
00155 
00156         return true;
00157     }
00158 
00164     public function before_path($path) {
00165         if ($this->path_is_selected($path)) {
00166             $this->startendinfo[] = array('path' => $path, 'action' => 'start');
00167         }
00168     }
00169 
00175     public function after_path($path) {
00176         $toprocess = false;
00177         // If the path being closed matches (same or parent) the first path in the stack
00178         // we process pending startend notifications until one matching end is found
00179         if ($element = reset($this->startendinfo)) {
00180             $elepath = $element['path'];
00181             $eleaction = $element['action'];
00182             if (strpos($elepath, $path) === 0) {
00183                 $toprocess = true;
00184             }
00185 
00186         // Also, if the stack of startend notifications is empty, we can process current end
00187         // path safely
00188         } else {
00189             $toprocess = true;
00190         }
00191         if ($this->path_is_selected($path)) {
00192             $this->startendinfo[] = array('path' => $path, 'action' => 'end');
00193         }
00194         // Send all the pending startend notifications if decided to do so
00195         if ($toprocess) {
00196             $this->process_pending_startend_notifications($path, 'end');
00197         }
00198     }
00199 
00200 
00201 // Protected API starts here
00202 
00212     protected function process_pending_startend_notifications($path, $action) {
00213 
00214         // Iterate until one matching path and action is found (or the array is empty)
00215         $elecount = count($this->startendinfo);
00216         $elematch = false;
00217         while ($elecount > 0 && !$elematch) {
00218             $element = array_shift($this->startendinfo);
00219             $elecount--;
00220             $elepath = $element['path'];
00221             $eleaction = $element['action'];
00222 
00223             if ($elepath == $path && $eleaction == $action) {
00224                 $elematch = true;
00225             }
00226 
00227             if ($eleaction == 'start') {
00228                 $this->notify_path_start($elepath);
00229             } else {
00230                 $this->notify_path_end($elepath);
00231             }
00232         }
00233     }
00234 
00235     protected function postprocess_chunk($data) {
00236         $this->dispatch_chunk($data);
00237     }
00238 
00239     protected function path_is_selected($path) {
00240         return in_array($path, $this->paths);
00241     }
00242 
00243     protected function path_is_selected_parent($path) {
00244         return in_array($path, $this->parentpaths);
00245     }
00246 
00250     protected function selected_parent_exists($path) {
00251         $parentpath = progressive_parser::dirname($path);
00252         while ($parentpath != '/') {
00253             if ($this->path_is_selected($parentpath)) {
00254                 return $parentpath;
00255             }
00256             $parentpath = progressive_parser::dirname($parentpath);
00257         }
00258         return false;
00259     }
00260 }
 All Data Structures Namespaces Files Functions Variables Enumerations