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