PageRenderTime 621ms CodeModel.GetById 96ms app.highlight 442ms RepoModel.GetById 62ms app.codeStats 1ms

/gforge/plugins/wiki/www/lib/XmlElement.php

https://github.com/neymanna/fusionforge
PHP | 645 lines | 554 code | 36 blank | 55 comment | 45 complexity | 48870bb3e35783784a9123ea5a013880 MD5 | raw file
  1<?php rcs_id('$Id: XmlElement.php,v 1.38 2005/10/10 19:36:09 rurban Exp $');
  2/**
  3 * Code for writing XML.
  4 * @package Markup
  5 * @author: Jeff Dairiki,
  6 *          Reini Urban (php5 tricks)
  7 *
  8 * WARNING: This module is very php5 sensitive. 
  9 *        Fixed for 1.3.9 and 1.3.11.
 10 *        With allow_call_time_pass_reference clean fixes.
 11 */
 12
 13/**
 14 * A sequence of (zero or more) XmlElements (possibly interspersed with
 15 * plain strings (CDATA).
 16 */
 17class XmlContent
 18{
 19    function XmlContent (/* ... */) {
 20        $this->_content = array();
 21        $this->_pushContent_array(func_get_args());
 22    }
 23
 24    function pushContent ($arg /*, ...*/) {
 25        if (func_num_args() > 1)
 26            $this->_pushContent_array(func_get_args());
 27        elseif (is_array($arg))
 28            $this->_pushContent_array($arg);
 29        else
 30            $this->_pushContent($arg);
 31    }
 32
 33    function _pushContent_array ($array) {
 34        foreach ($array as $item) {
 35            if (is_array($item))
 36                $this->_pushContent_array($item);
 37            else
 38                $this->_pushContent($item);
 39        }
 40    }
 41
 42    function _pushContent ($item) {
 43        if (strtolower(get_class($item)) == 'xmlcontent')
 44            array_splice($this->_content, count($this->_content), 0,
 45                         $item->_content);
 46        else
 47            $this->_content[] = $item;
 48    }
 49
 50    function unshiftContent ($arg /*, ...*/) {
 51        if (func_num_args() > 1)
 52            $this->_unshiftContent_array(func_get_args());
 53        elseif (is_array($arg))
 54            $this->_unshiftContent_array($arg);
 55        else
 56            $this->_unshiftContent($arg);
 57    }
 58
 59    function _unshiftContent_array ($array) {
 60        foreach (array_reverse($array) as $item) {
 61            if (is_array($item))
 62                $this->_unshiftContent_array($item);
 63            else
 64                $this->_unshiftContent($item);
 65        }
 66    }
 67
 68    function _unshiftContent ($item) {
 69        if (strtolower(get_class($item)) == 'xmlcontent')
 70            array_splice($this->_content, 0, 0, $item->_content);
 71        else
 72            array_unshift($this->_content, $item);
 73    }
 74    
 75    function getContent () {
 76        return $this->_content;
 77    }
 78
 79    function setContent ($arg /* , ... */) {
 80        $this->_content = array();
 81        $this->_pushContent_array(func_get_args());
 82    }
 83
 84    function printXML () {
 85        foreach ($this->_content as $item) {
 86            if (is_object($item)) {
 87                if (method_exists($item, 'printXML'))
 88                    $item->printXML();
 89                elseif (method_exists($item, 'asXML'))
 90                    echo $item->asXML();
 91                elseif (method_exists($item, 'asString'))
 92                    echo $this->_quote($item->asString());
 93                else
 94                    printf("==Object(%s)==", get_class($item));
 95            }
 96            else
 97                echo $this->_quote((string) $item);
 98        }
 99    }
100
101    function asXML () {
102        $xml = '';
103        foreach ($this->_content as $item) {
104            if (is_object($item)) {
105                if (method_exists($item, 'asXML'))
106                    $xml .= $item->asXML();
107                elseif (method_exists($item, 'asString'))
108                    $xml .= $this->_quote($item->asString());
109                else
110                    $xml .= sprintf("==Object(%s)==", get_class($item));
111            }
112            else
113                $xml .= $this->_quote((string) $item);
114        }
115        return $xml;
116    }
117
118    function asPDF () {
119        $pdf = '';
120        foreach ($this->_content as $item) {
121            if (is_object($item)) {
122                if (method_exists($item, 'asPDF'))
123                    $pdf .= $item->asPDF();
124                elseif (method_exists($item, 'asString'))
125                    $pdf .= $this->_quote($item->asString());
126                else
127                    $pdf .= sprintf("==Object(%s)==", get_class($item));
128            }
129            else
130                $pdf .= $this->_quote((string) $item);
131        }
132        return $pdf;
133    }
134
135    function asString () {
136        $val = '';
137        foreach ($this->_content as $item) {
138            if (is_object($item)) {
139                if (method_exists($item, 'asString'))
140                    $val .= $item->asString();
141                else
142                    $val .= sprintf("==Object(%s)==", get_class($item));
143            }
144            else
145                $val .= (string) $item;
146        }
147        return trim($val);
148    }
149
150
151    /**
152     * See if element is empty.
153     *
154     * Empty means it has no content.
155     * @return bool True if empty.
156     */
157    function isEmpty () {
158        if (empty($this->_content))
159            return true;
160        foreach ($this->_content as $x) {
161            if (is_string($x) ? strlen($x) : !empty($x))
162                return false;
163        }
164        return true;
165    }
166    
167    function _quote ($string) {
168    	if (!$string) return $string;
169        if (check_php_version(4,1) and isset($GLOBALS['charset']))
170            return htmlspecialchars($string, ENT_COMPAT, $GLOBALS['charset']);
171        else
172            return htmlspecialchars($string);
173    }
174};
175
176/**
177 * An XML element.
178 *
179 * @param $tagname string Tag of html element.
180 */
181class XmlElement extends XmlContent
182{
183    function XmlElement ($tagname /* , $attr_or_content , ...*/) {
184        //FIXME: php5 incompatible
185        $this->XmlContent();
186        $this->_init(func_get_args());
187    }
188
189    function _init ($args) {
190        if (!is_array($args))
191            $args = func_get_args();
192
193        assert(count($args) >= 1);
194        //assert(is_string($args[0]));
195        $this->_tag = array_shift($args);
196        
197        if ($args && is_array($args[0]))
198            $this->_attr = array_shift($args);
199        else {
200            $this->_attr = array();
201            if ($args && $args[0] === false)
202                array_shift($args);
203        }
204
205        $this->setContent($args);
206    }
207    
208    /** Methods only needed for XmlParser,
209     *  to be fully compatible to perl Html::Element
210     */
211    // doesn't yet work with php5 as __destruct()
212    function _destruct () {
213        if ($this->hasChildren()) {
214            foreach ($this->getChildren() as $node) {
215                $node->_destruct();
216            }
217        }
218        unset($this->_tag);
219        unset($this->_attr);
220        unset($this->_content);
221    }
222    
223    function getChildren () {
224        return $this->_children;
225    }
226
227    function hasChildren () {
228        return !empty($this->_children);
229    }
230    /* End XmlParser Methods
231     */
232
233    function getTag () {
234        return $this->_tag;
235    }
236    
237    function setAttr ($attr, $value = false) {
238	if (is_array($attr)) {
239            assert($value === false);
240            foreach ($attr as $a => $v) {
241                $this->_attr[strtolower($a)] = $v;
242		//$this->set($a, $v);
243            }
244            return;
245	}
246
247        assert(is_string($attr));
248            
249        if ($value === false) {
250            unset($this->_attr[$attr]);
251        }
252        else {
253            if (is_bool($value))
254                $value = $attr;
255            $this->_attr[$attr] = (string) $value;
256        }
257
258	if ($attr == 'class')
259	    unset($this->_classes);
260    }
261
262    function getAttr ($attr) {
263	if ($attr == 'class')
264	    $this->_setClasses();
265
266	if (isset($this->_attr[strtolower($attr)]))
267	    return $this->_attr[strtolower($attr)];
268	else
269	    return false;
270    }
271
272    function _getClasses() {
273	if (!isset($this->_classes)) {
274	    $this->_classes = array();
275	    if (isset($this->_attr['class'])) {
276		$classes = explode(' ', (string) $this->_attr['class']);
277		foreach ($classes as $class) {
278		    $class = trim($class);
279		    if ($class)
280			$this->_classes[$class] = $class;
281		}
282	    }
283	}
284	return $this->_classes;
285    }
286
287    function _setClasses() {
288	if (isset($this->_classes)) {
289	    if ($this->_classes)
290		$this->_attr['class'] = join(' ', $this->_classes);
291	    else
292		unset($this->_attr['class']);
293	}
294    }
295
296    /**
297     * Manipulate the elements CSS class membership.
298     *
299     * This adds or remove an elements membership
300     * in a give CSS class.
301     *
302     * @param $class string
303     *
304     * @param $in_class bool
305     *   If true (the default) the element is added to class $class.
306     *   If false, the element is removed from the class.
307     */
308    function setInClass($class, $in_class=true) {
309	$this->_getClasses();
310	$class = trim($class);
311	if ($in_class)
312	    $this->_classes[$class] = $class;
313	else 
314	    unset($this->_classes[$class]);
315    }
316
317    /**
318     * Is element in a given (CSS) class?
319     *
320     * This checks for the presence of a particular class in the
321     * elements 'class' attribute.
322     *
323     * @param $class string  The class to check for.
324     * @return bool True if the element is a member of $class.
325     */
326    function inClass($class) {
327	$this->_parseClasses();
328	return isset($this->_classes[trim($class)]);
329    }
330
331    function startTag() {
332        $start = "<" . $this->_tag;
333	$this->_setClasses();
334        foreach ($this->_attr as $attr => $val) {
335            if (is_bool($val)) {
336                if (!$val)
337                    continue;
338                $val = $attr;
339            }
340            $qval = str_replace("\"", '&quot;', $this->_quote((string)$val));
341            $start .= " $attr=\"$qval\"";
342        }
343        $start .= ">";
344        return $start;
345    }
346
347    function emptyTag() {
348        return substr($this->startTag(), 0, -1) . "/>";
349    }
350
351    
352    function endTag() {
353        return "</$this->_tag>";
354    }
355    
356        
357    function printXML () {
358        if ($this->isEmpty())
359            echo $this->emptyTag();
360        else {
361            echo $this->startTag();
362            // FIXME: The next two lines could be removed for efficiency
363            if (!$this->hasInlineContent())
364                echo "\n";
365            XmlContent::printXML();
366            echo "</$this->_tag>";
367        }
368        if (!$this->isInlineElement())
369            echo "\n";
370    }
371
372    function asXML () {
373        if ($this->isEmpty()) {
374            $xml = $this->emptyTag();
375        }
376        else {
377            $xml = $this->startTag();
378            // FIXME: The next two lines could be removed for efficiency
379            if (!$this->hasInlineContent())
380                $xml .= "\n";
381            $xml .= XmlContent::asXML();
382            $xml .= "</$this->_tag>";
383        }
384        if (!$this->isInlineElement())
385            $xml .= "\n";
386        return $xml;
387    }
388
389    /**
390     * Can this element have inline content?
391     *
392     * This is a hack, but is probably the best one can do without
393     * knowledge of the DTD...
394     */
395    function hasInlineContent () {
396        // This is a hack.
397        if (empty($this->_content))
398            return true;
399        if (is_object($this->_content[0]))
400            return false;
401        return true;
402    }
403    
404    /**
405     * Is this element part of inline content?
406     *
407     * This is a hack, but is probably the best one can do without
408     * knowledge of the DTD...
409     */
410    function isInlineElement () {
411        return false;
412    }
413    
414};
415
416class RawXml {
417    function RawXml ($xml_text) {
418        $this->_xml = $xml_text;
419    }
420
421    function printXML () {
422        echo $this->_xml;
423    }
424
425    function asXML () {
426        return $this->_xml;
427    }
428
429    function isEmpty () {
430        return empty($this->_xml);
431    }
432}
433
434class FormattedText {
435    function FormattedText ($fs /* , ... */) {
436        if ($fs !== false) {
437            $this->_init(func_get_args());
438        }
439    }
440
441    function _init ($args) {
442        $this->_fs = array_shift($args);
443
444        // PHP's sprintf doesn't support variable width specifiers,
445        // like sprintf("%*s", 10, "x"); --- so we won't either.
446        $m = array();
447        if (! preg_match_all('/(?<!%)%(\d+)\$/x', $this->_fs, $m)) {
448            $this->_args  = $args;
449        }
450        else {
451            // Format string has '%2$s' style argument reordering.
452            // PHP doesn't support this.
453            if (preg_match('/(?<!%)%[- ]?\d*[^- \d$]/x', $this->_fs)) // $fmt
454                // literal variable name substitution only to keep locale
455                // strings uncluttered
456                trigger_error(sprintf(_("Can't mix '%s' with '%s' type format strings"),
457                                      '%1\$s','%s'), E_USER_WARNING);
458        
459            $this->_fs = preg_replace('/(?<!%)%\d+\$/x', '%', $this->_fs);
460
461            $this->_args = array();
462            foreach($m[1] as $argnum) {
463                if ($argnum < 1 || $argnum > count($args))
464                    trigger_error(sprintf("%s: argument index out of range", 
465                                          $argnum), E_USER_WARNING);
466                $this->_args[] = $args[$argnum - 1];
467            }
468        }
469    }
470
471    function asXML () {
472        // Not all PHP's have vsprintf, so...
473        $args[] = XmlElement::_quote((string)$this->_fs);
474        foreach ($this->_args as $arg)
475            $args[] = AsXML($arg);
476        return call_user_func_array('sprintf', $args);
477    }
478
479    function printXML () {
480        // Not all PHP's have vsprintf, so...
481        $args[] = XmlElement::_quote((string)$this->_fs);
482        foreach ($this->_args as $arg)
483            $args[] = AsXML($arg);
484        call_user_func_array('printf', $args);
485    }
486
487    function asString() {
488        $args[] = $this->_fs;
489        foreach ($this->_args as $arg)
490            $args[] = AsString($arg);
491        return call_user_func_array('sprintf', $args);
492    }
493}
494
495/**
496 * PHP5 compatibility
497 * Error[2048]: Non-static method XmlContent::_quote() should not be called statically
498 */
499function XmlContent_quote ($string) {
500    if (!$string) return $string;
501    if (check_php_version(4,1) and isset($GLOBALS['charset']))
502        return htmlspecialchars($string, ENT_COMPAT, $GLOBALS['charset']);
503    else
504        return htmlspecialchars($string);
505}
506
507function PrintXML ($val /* , ... */ ) {
508    if (func_num_args() > 1) {
509        foreach (func_get_args() as $arg)
510            PrintXML($arg);
511    }
512    elseif (is_object($val)) {
513        if (method_exists($val, 'printXML'))
514            $val->printXML();
515        elseif (method_exists($val, 'asXML')) {
516            echo $val->asXML();
517        }
518        elseif (method_exists($val, 'asString'))
519            echo XmlContent_quote($val->asString());
520        else
521            printf("==Object(%s)==", get_class($val));
522    }
523    elseif (is_array($val)) {
524        // DEPRECATED:
525        // Use XmlContent objects instead of arrays for collections of XmlElements.
526        trigger_error("Passing arrays to PrintXML() is deprecated: (" . AsXML($val, true) . ")",
527                      E_USER_NOTICE);
528        foreach ($val as $x)
529            PrintXML($x);
530    }
531    else
532        echo (string)XmlContent_quote((string)$val);
533}
534
535function AsXML ($val /* , ... */) {
536    static $nowarn;
537
538    if (func_num_args() > 1) {
539        $xml = '';
540        foreach (func_get_args() as $arg)
541            $xml .= AsXML($arg);
542        return $xml;
543    }
544    elseif (is_object($val)) {
545        if (method_exists($val, 'asXML'))
546            return $val->asXML();
547        elseif (method_exists($val, 'asString'))
548            return XmlContent_quote($val->asString());
549        else
550            return sprintf("==Object(%s)==", get_class($val));
551    }
552    elseif (is_array($val)) {
553        // DEPRECATED:
554        // Use XmlContent objects instead of arrays for collections of XmlElements.
555        if (empty($nowarn)) {
556            $nowarn = true;
557            trigger_error("Passing arrays to AsXML() is deprecated: (" . AsXML($val) . ")",
558                          E_USER_NOTICE);
559            unset($nowarn);
560        }
561        $xml = '';
562        foreach ($val as $x)
563            $xml .= AsXML($x);
564        return $xml;
565    }
566    else
567        return XmlContent_quote((string)$val);
568}
569
570function AsString ($val) {
571    if (func_num_args() > 1) {
572        $str = '';
573        foreach (func_get_args() as $arg)
574            $str .= AsString($arg);
575        return $str;
576    }
577    elseif (is_object($val)) {
578        if (method_exists($val, 'asString'))
579            return $val->asString();
580        else
581            return sprintf("==Object(%s)==", get_class($val));
582    }
583    elseif (is_array($val)) {
584        // DEPRECATED:
585        // Use XmlContent objects instead of arrays for collections of XmlElements.
586        trigger_error("Passing arrays to AsString() is deprecated", E_USER_NOTICE);
587        $str = '';
588        foreach ($val as $x)
589            $str .= AsString($x);
590        return $str;
591    }
592    
593    return (string) $val;
594}
595
596
597function fmt ($fs /* , ... */) {
598    $s = new FormattedText(false);
599
600    $args = func_get_args();
601    $args[0] = _($args[0]);
602    $s->_init($args);
603    return $s;
604}
605
606// $Log: XmlElement.php,v $
607// Revision 1.38  2005/10/10 19:36:09  rurban
608// fix comment
609//
610// Revision 1.37  2005/01/25 07:04:27  rurban
611// case-sensitive for php5
612//
613// Revision 1.36  2004/12/06 19:49:56  rurban
614// enable action=remove which is undoable and seeable in RecentChanges: ADODB ony for now.
615// renamed delete_page to purge_page.
616// enable action=edit&version=-1 to force creation of a new version.
617// added BABYCART_PATH config
618// fixed magiqc in adodb.inc.php
619// and some more docs
620//
621// Revision 1.35  2004/11/21 11:59:18  rurban
622// remove final \n to be ob_cache independent
623//
624// Revision 1.34  2004/10/12 13:13:19  rurban
625// php5 compatibility (5.0.1 ok)
626//
627// Revision 1.33  2004/07/02 09:55:58  rurban
628// more stability fixes: new DISABLE_GETIMAGESIZE if your php crashes when loading LinkIcons: failing getimagesize in old phps; blockparser stabilized
629//
630// Revision 1.32  2004/06/20 15:30:05  rurban
631// get_class case-sensitivity issues
632//
633// Revision 1.31  2004/06/20 14:42:54  rurban
634// various php5 fixes (still broken at blockparser)
635//
636
637// (c-file-style: "gnu")
638// Local Variables:
639// mode: php
640// tab-width: 8
641// c-basic-offset: 4
642// c-hanging-comment-ender-p: nil
643// indent-tabs-mode: nil
644// End:   
645?>