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