1 <?php rcs_id('$Id: XmlElement.php,v 1.32 2004-06-20 15:30:05 rurban Exp $');
3 * Code for writing XML.
5 * @author: Jeff Dairiki
7 * FIXME: This module is very php5 sensitive: It was fixed for 1.3.9,
8 * but is again broken with the 1.3.11
9 * allow_call_time_pass_reference clean fixes
13 * A sequence of (zero or more) XmlElements (possibly interspersed with
14 * plain strings (CDATA).
18 function XmlContent (/* ... */) {
19 $this->_content = array();
20 $this->_pushContent_array(func_get_args());
23 function pushContent ($arg /*, ...*/) {
24 if (func_num_args() > 1)
25 $this->_pushContent_array(func_get_args());
26 elseif (is_array($arg))
27 $this->_pushContent_array($arg);
29 $this->_pushContent($arg);
32 function _pushContent_array ($array) {
33 foreach ($array as $item) {
35 $this->_pushContent_array($item);
37 $this->_pushContent($item);
41 function _pushContent ($item) {
42 if (strtolower(get_class($item)) == 'xmlcontent')
43 array_splice($this->_content, count($this->_content), 0,
46 $this->_content[] = $item;
49 function unshiftContent ($arg /*, ...*/) {
50 if (func_num_args() > 1)
51 $this->_unshiftContent_array(func_get_args());
52 elseif (is_array($arg))
53 $this->_unshiftContent_array($arg);
55 $this->_unshiftContent($arg);
58 function _unshiftContent_array ($array) {
59 foreach (array_reverse($array) as $item) {
61 $this->_unshiftContent_array($item);
63 $this->_unshiftContent($item);
67 function _unshiftContent ($item) {
68 if (strtolower(get_class($item)) == 'xmlcontent')
69 array_splice($this->_content, 0, 0, $item->_content);
71 array_unshift($this->_content, $item);
74 function getContent () {
75 return $this->_content;
78 function setContent ($arg /* , ... */) {
79 $this->_content = array();
80 $this->_pushContent_array(func_get_args());
83 function printXML () {
84 foreach ($this->_content as $item) {
85 if (is_object($item)) {
86 if (method_exists($item, 'printxml'))
88 elseif (method_exists($item, 'asxml'))
90 elseif (method_exists($item, 'asstring'))
91 echo $this->_quote($item->asString());
93 printf("==Object(%s)==", get_class($item));
96 echo $this->_quote((string) $item);
102 foreach ($this->_content as $item) {
103 if (is_object($item)) {
104 if (method_exists($item, 'asxml'))
105 $xml .= $item->asXML();
106 elseif (method_exists($item, 'asstring'))
107 $xml .= $this->_quote($item->asString());
109 $xml .= sprintf("==Object(%s)==", get_class($item));
112 $xml .= $this->_quote((string) $item);
119 foreach ($this->_content as $item) {
120 if (is_object($item)) {
121 if (method_exists($item, 'aspdf'))
122 $pdf .= $item->asPDF();
123 elseif (method_exists($item, 'asstring'))
124 $pdf .= $this->_quote($item->asString());
126 $pdf .= sprintf("==Object(%s)==", get_class($item));
129 $pdf .= $this->_quote((string) $item);
134 function asString () {
136 foreach ($this->_content as $item) {
137 if (is_object($item)) {
138 if (method_exists($item, 'asstring'))
139 $val .= $item->asString();
141 $val .= sprintf("==Object(%s)==", get_class($item));
144 $val .= (string) $item;
151 * See if element is empty.
153 * Empty means it has no content.
154 * @return bool True if empty.
156 function isEmpty () {
157 if (empty($this->_content))
159 foreach ($this->_content as $x) {
160 if (is_string($x) ? strlen($x) : !empty($x))
166 function _quote ($string) {
167 if (!$string) return $string;
168 if (check_php_version(4,1) and isset($GLOBALS['charset']))
169 return htmlspecialchars($string, ENT_COMPAT, $GLOBALS['charset']);
171 return htmlspecialchars($string);
178 * @param $tagname string Tag of html element.
180 class XmlElement extends XmlContent
182 function XmlElement ($tagname /* , $attr_or_content , ...*/) {
183 //FIXME: php5 incompatible
185 $this->_init(func_get_args());
188 function _init ($args) {
189 if (!is_array($args))
190 $args = func_get_args();
192 assert(count($args) >= 1);
193 //assert(is_string($args[0]));
194 $this->_tag = array_shift($args);
196 if ($args && is_array($args[0]))
197 $this->_attr = array_shift($args);
199 $this->_attr = array();
200 if ($args && $args[0] === false)
204 $this->setContent($args);
207 /** Methods only needed for XmlParser,
208 * to be fully compatible to perl Html::Element
210 // doesn't yet work with php5 as __destruct()
211 function _destruct () {
212 if ($this->hasChildren()) {
213 foreach ($this->getChildren() as $node) {
219 unset($this->_content);
222 function getChildren () {
223 return $this->_children;
226 function hasChildren () {
227 return !empty($this->_children);
229 /* End XmlParser Methods
236 function setAttr ($attr, $value = false) {
237 if (is_array($attr)) {
238 assert($value === false);
239 foreach ($attr as $a => $v) {
240 $this->_attr[strtolower($a)] = $v;
241 //$this->set($a, $v);
246 assert(is_string($attr));
248 if ($value === false) {
249 unset($this->_attr[$attr]);
254 $this->_attr[$attr] = (string) $value;
257 if ($attr == 'class')
258 unset($this->_classes);
261 function getAttr ($attr) {
262 if ($attr == 'class')
263 $this->_setClasses();
265 if (isset($this->_attr[$attr]))
266 return $this->_attr[$attr];
271 function _getClasses() {
272 if (!isset($this->_classes)) {
273 $this->_classes = array();
274 if (isset($this->_attr['class'])) {
275 $classes = explode(' ', (string) $this->_attr['class']);
276 foreach ($classes as $class) {
277 $class = trim($class);
279 $this->_classes[$class] = $class;
283 return $this->_classes;
286 function _setClasses() {
287 if (isset($this->_classes)) {
289 $this->_attr['class'] = join(' ', $this->_classes);
291 unset($this->_attr['class']);
296 * Manipulate the elements CSS class membership.
298 * This adds or remove an elements membership
299 * in a give CSS class.
301 * @param $class string
303 * @param $in_class bool
304 * If true (the default) the element is added to class $class.
305 * If false, the element is removed from the class.
307 function setInClass($class, $in_class=true) {
308 $this->_getClasses();
309 $class = trim($class);
311 $this->_classes[$class] = $class;
313 unset($this->_classes[$class]);
317 * Is element in a given (CSS) class?
319 * This checks for the presence of a particular class in the
320 * elements 'class' attribute.
322 * @param $class string The class to check for.
323 * @return bool True if the element is a member of $class.
325 function inClass($class) {
326 $this->_parseClasses();
327 return isset($this->_classes[trim($class)]);
330 function startTag() {
331 $start = "<" . $this->_tag;
332 $this->_setClasses();
333 foreach ($this->_attr as $attr => $val) {
339 $qval = str_replace("\"", '"', $this->_quote((string)$val));
340 $start .= " $attr=\"$qval\"";
346 function emptyTag() {
347 return substr($this->startTag(), 0, -1) . "/>";
352 return "</$this->_tag>";
356 function printXML () {
357 if ($this->isEmpty())
358 echo $this->emptyTag();
360 echo $this->startTag();
361 // FIXME: The next two lines could be removed for efficiency
362 if (!$this->hasInlineContent())
364 XmlContent::printXML();
365 echo "</$this->_tag>";
367 if (!$this->isInlineElement())
372 if ($this->isEmpty()) {
373 $xml = $this->emptyTag();
376 $xml = $this->startTag();
377 // FIXME: The next two lines could be removed for efficiency
378 if (!$this->hasInlineContent())
380 $xml .= XmlContent::asXML();
381 $xml .= "</$this->_tag>";
383 if (!$this->isInlineElement())
389 * Can this element have inline content?
391 * This is a hack, but is probably the best one can do without
392 * knowledge of the DTD...
394 function hasInlineContent () {
396 if (empty($this->_content))
398 if (is_object($this->_content[0]))
404 * Is this element part of inline content?
406 * This is a hack, but is probably the best one can do without
407 * knowledge of the DTD...
409 function isInlineElement () {
416 function RawXml ($xml_text) {
417 $this->_xml = $xml_text;
420 function printXML () {
428 function isEmpty () {
429 return empty($this->_xml);
433 class FormattedText {
434 function FormattedText ($fs /* , ... */) {
436 $this->_init(func_get_args());
440 function _init ($args) {
441 $this->_fs = array_shift($args);
443 // PHP's sprintf doesn't support variable width specifiers,
444 // like sprintf("%*s", 10, "x"); --- so we won't either.
446 if (! preg_match_all('/(?<!%)%(\d+)\$/x', $this->_fs, $m)) {
447 $this->_args = $args;
450 // Format string has '%2$s' style argument reordering.
451 // PHP doesn't support this.
452 if (preg_match('/(?<!%)%[- ]?\d*[^- \d$]/x', $this->_fs)) // $fmt
453 // literal variable name substitution only to keep locale
454 // strings uncluttered
455 trigger_error(sprintf(_("Can't mix '%s' with '%s' type format strings"),
456 '%1\$s','%s'), E_USER_WARNING);
458 $this->_fs = preg_replace('/(?<!%)%\d+\$/x', '%', $this->_fs);
460 $this->_args = array();
461 foreach($m[1] as $argnum) {
462 if ($argnum < 1 || $argnum > count($args))
463 trigger_error(sprintf("%s: argument index out of range",
464 $argnum), E_USER_WARNING);
465 $this->_args[] = $args[$argnum - 1];
471 // Not all PHP's have vsprintf, so...
472 $args[] = XmlElement::_quote((string)$this->_fs);
473 foreach ($this->_args as $arg)
474 $args[] = AsXML($arg);
475 return call_user_func_array('sprintf', $args);
478 function printXML () {
479 // Not all PHP's have vsprintf, so...
480 $args[] = XmlElement::_quote((string)$this->_fs);
481 foreach ($this->_args as $arg)
482 $args[] = AsXML($arg);
483 call_user_func_array('printf', $args);
486 function asString() {
487 $args[] = $this->_fs;
488 foreach ($this->_args as $arg)
489 $args[] = AsString($arg);
490 return call_user_func_array('sprintf', $args);
494 function PrintXML ($val /* , ... */ ) {
495 if (func_num_args() > 1) {
496 foreach (func_get_args() as $arg)
499 elseif (is_object($val)) {
500 if (method_exists($val, 'printxml'))
502 elseif (method_exists($val, 'asxml')) {
505 elseif (method_exists($val, 'asstring'))
506 echo XmlContent::_quote($val->asString());
508 printf("==Object(%s)==", get_class($val));
510 elseif (is_array($val)) {
512 // Use XmlContent objects instead of arrays for collections of XmlElements.
513 trigger_error("Passing arrays to PrintXML() is deprecated: (" . AsXML($val, true) . ")",
519 echo (string)XmlContent::_quote((string)$val);
522 function AsXML ($val /* , ... */) {
525 if (func_num_args() > 1) {
527 foreach (func_get_args() as $arg)
531 elseif (is_object($val)) {
532 if (method_exists($val, 'asxml'))
533 return $val->asXML();
534 elseif (method_exists($val, 'asstring'))
535 return XmlContent::_quote($val->asString());
537 return sprintf("==Object(%s)==", get_class($val));
539 elseif (is_array($val)) {
541 // Use XmlContent objects instead of arrays for collections of XmlElements.
542 if (empty($nowarn)) {
544 trigger_error("Passing arrays to AsXML() is deprecated: (" . AsXML($val) . ")",
554 return XmlContent::_quote((string)$val);
557 function AsString ($val) {
558 if (func_num_args() > 1) {
560 foreach (func_get_args() as $arg)
561 $str .= AsString($arg);
564 elseif (is_object($val)) {
565 if (method_exists($val, 'asstring'))
566 return $val->asString();
568 return sprintf("==Object(%s)==", get_class($val));
570 elseif (is_array($val)) {
572 // Use XmlContent objects instead of arrays for collections of XmlElements.
573 trigger_error("Passing arrays to AsString() is deprecated", E_USER_NOTICE);
576 $str .= AsString($x);
580 return (string) $val;
584 function fmt ($fs /* , ... */) {
585 $s = new FormattedText(false);
587 $args = func_get_args();
588 $args[0] = _($args[0]);
593 // $Log: not supported by cvs2svn $
594 // Revision 1.31 2004/06/20 14:42:54 rurban
595 // various php5 fixes (still broken at blockparser)
598 // (c-file-style: "gnu")
603 // c-hanging-comment-ender-p: nil
604 // indent-tabs-mode: nil