Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/backup/util/xml/xml_writer.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 
00040 class xml_writer {
00041 
00042     protected $output;     // @xml_output that defines how to output XML
00043     protected $contenttransformer; // @xml_contenttransformer to modify contents before output
00044 
00045     protected $prologue;   // Complete string prologue we want to use
00046     protected $xmlschema;  // URI to nonamespaceschema to be added to main tag
00047 
00048     protected $casefolding; // To define if xml tags must be uppercase (true) or not (false)
00049 
00050     protected $level;      // current number of open tags, useful for indent text
00051     protected $opentags;   // open tags accumulator, to check for errors
00052     protected $lastwastext;// to know when we are writing after text content
00053     protected $nullcontent;// to know if we are going to write one tag with null content
00054 
00055     protected $running; // To know if writer is running
00056 
00057     public function __construct($output, $contenttransformer = null, $casefolding = false) {
00058         if (!$output instanceof xml_output) {
00059             throw new xml_writer_exception('invalid_xml_output');
00060         }
00061         if (!is_null($contenttransformer) && !$contenttransformer instanceof xml_contenttransformer) {
00062             throw new xml_writer_exception('invalid_xml_contenttransformer');
00063         }
00064 
00065         $this->output = $output;
00066         $this->contenttransformer = $contenttransformer;
00067 
00068         $this->prologue  = null;
00069         $this->xmlschema = null;
00070 
00071         $this->casefolding = $casefolding;
00072 
00073         $this->level    = 0;
00074         $this->opentags = array();
00075         $this->lastwastext = false;
00076         $this->nullcontent = false;
00077 
00078         $this->running = null;
00079     }
00080 
00085     public function start() {
00086         if ($this->running === true) {
00087             throw new xml_writer_exception('xml_writer_already_started');
00088         }
00089         if ($this->running === false) {
00090             throw new xml_writer_exception('xml_writer_already_stopped');
00091         }
00092         $this->output->start(); // Initialize whatever we need in output
00093         if (!is_null($this->prologue)) { // Output prologue
00094             $this->write($this->prologue);
00095         } else {
00096             $this->write($this->get_default_prologue());
00097         }
00098         $this->running = true;
00099     }
00100 
00105     public function stop() {
00106         if (is_null($this->running)) {
00107             throw new xml_writer_exception('xml_writer_not_started');
00108         }
00109         if ($this->running === false) {
00110             throw new xml_writer_exception('xml_writer_already_stopped');
00111         }
00112         if ($this->level > 0) { // Cannot stop if not at level 0, remaining open tags
00113             throw new xml_writer_exception('xml_writer_open_tags_remaining');
00114         }
00115         $this->output->stop();
00116         $this->running = false;
00117     }
00118 
00122     public function set_nonamespace_schema($uri) {
00123         if ($this->running) {
00124             throw new xml_writer_exception('xml_writer_already_started');
00125         }
00126         $this->xmlschema = $uri;
00127     }
00128 
00132     public function set_prologue($prologue) {
00133         if ($this->running) {
00134             throw new xml_writer_exception('xml_writer_already_started');
00135         }
00136         $this->prologue = $prologue;
00137     }
00138 
00142     public function begin_tag($tag, $attributes = null) {
00143         // TODO: chek the tag name is valid
00144         $pre = $this->level ? "\n" . str_repeat(' ', $this->level * 2) : ''; // Indent
00145         $tag = $this->casefolding ? strtoupper($tag) : $tag; // Follow casefolding
00146         $end = $this->nullcontent ? ' /' : ''; // Tag without content, close it
00147 
00148         // Build attributes output
00149         $attrstring = '';
00150         if (!empty($attributes) && is_array($attributes)) {
00151             // TODO: check the attr name is valid
00152             foreach ($attributes as $name => $value) {
00153                 $name = $this->casefolding ? strtoupper($name) : $name; // Follow casefolding
00154                 $attrstring .= ' ' . $name . '="'.
00155                     $this->xml_safe_attr_content($value) . '"';
00156             }
00157         }
00158 
00159         // Optional xml schema definition (level 0 only)
00160         $schemastring = '';
00161         if ($this->level == 0 && !empty($this->xmlschema)) {
00162             $schemastring .= "\n    " . 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' .
00163                              "\n    " . 'xsi:noNamespaceSchemaLocation="' . $this->xml_safe_attr_content($this->xmlschema) . '"';
00164         }
00165 
00166         // Send to xml_output
00167         $this->write($pre . '<' . $tag . $attrstring . $schemastring . $end . '>');
00168 
00169         // Acumulate the tag and inc level
00170         if (!$this->nullcontent) {
00171             array_push($this->opentags, $tag);
00172             $this->level++;
00173         }
00174         $this->lastwastext = false;
00175     }
00176 
00180     public function end_tag($tag) {
00181         // TODO: check the tag name is valid
00182 
00183         if ($this->level == 0) { // Nothing to end, already at level 0
00184             throw new xml_writer_exception('xml_writer_end_tag_no_match');
00185         }
00186 
00187         $pre = $this->lastwastext ? '' : "\n" . str_repeat(' ', ($this->level - 1) * 2); // Indent
00188         $tag = $this->casefolding ? strtoupper($tag) : $tag; // Follow casefolding
00189 
00190         $lastopentag = array_pop($this->opentags);
00191 
00192         if ($tag != $lastopentag) {
00193             $a = new stdclass();
00194             $a->lastopen = $lastopentag;
00195             $a->tag = $tag;
00196             throw new xml_writer_exception('xml_writer_end_tag_no_match', $a);
00197         }
00198 
00199         // Send to xml_output
00200         $this->write($pre . '</' . $tag . '>');
00201 
00202         $this->level--;
00203         $this->lastwastext = false;
00204     }
00205 
00206 
00210     public function full_tag($tag, $content = null, $attributes = null) {
00211         $content = $this->text_content($content); // First of all, apply transformations
00212         $this->nullcontent = is_null($content) ? true : false; // Is it null content
00213         $this->begin_tag($tag, $attributes);
00214         if (!$this->nullcontent) {
00215             $this->write($content);
00216             $this->lastwastext = true;
00217             $this->end_tag($tag);
00218         }
00219     }
00220 
00221 
00222 // Protected API starts here
00223 
00227     protected function write($output) {
00228         $this->output->write($output);
00229     }
00230 
00234     protected function get_default_prologue() {
00235         return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
00236     }
00237 
00243     protected function xml_safe_attr_content($content) {
00244         return htmlspecialchars($this->xml_safe_utf8($content), ENT_COMPAT);
00245     }
00246 
00251     protected function xml_safe_text_content($content) {
00252         return htmlspecialchars($this->xml_safe_utf8($content), ENT_NOQUOTES);
00253     }
00254 
00262     protected function xml_safe_utf8($content) {
00263         $content = preg_replace('/[\x-\x8\xb-\xc\xe-\x1f\x7f]/is','', $content); // clean CTRL chars
00264         $content = preg_replace("/\r\n|\r/", "\n", $content); // Normalize line&return=>line
00265         return $content;
00266     }
00267 
00271     protected function text_content($content) {
00272         if (!is_null($this->contenttransformer)) { // Apply content transformation
00273             $content = $this->contenttransformer->process($content);
00274         }
00275         return is_null($content) ? null : $this->xml_safe_text_content($content); // Safe UTF-8 and encode
00276     }
00277 }
00278 
00279 /*
00280  * Exception class used by all the @xml_writer stuff
00281  */
00282 class xml_writer_exception extends moodle_exception {
00283 
00284     public function __construct($errorcode, $a=NULL, $debuginfo=null) {
00285         parent::__construct($errorcode, 'error', '', $a, $debuginfo);
00286     }
00287 }
 All Data Structures Namespaces Files Functions Variables Enumerations