1 <?php rcs_id('$Id: XmlElement.php,v 1.28 2004-05-24 17:31:31 rurban Exp $');
3 * Code for writing XML.
4 * @author: Jeff Dairiki
9 * A sequence of (zero or more) XmlElements (possibly interspersed with
10 * plain strings (CDATA).
14 function XmlContent (/* ... */) {
15 $this->_content = array();
16 $this->_pushContent_array(func_get_args());
19 function pushContent ($arg /*, ...*/) {
20 if (func_num_args() > 1)
21 $this->_pushContent_array(func_get_args());
22 elseif (is_array($arg))
23 $this->_pushContent_array($arg);
25 $this->_pushContent($arg);
28 function _pushContent_array ($array) {
29 foreach ($array as $item) {
31 $this->_pushContent_array($item);
33 $this->_pushContent($item);
37 function _pushContent ($item) {
38 if (get_class($item) == 'xmlcontent')
39 array_splice($this->_content, count($this->_content), 0,
42 $this->_content[] = $item;
45 function unshiftContent ($arg /*, ...*/) {
46 if (func_num_args() > 1)
47 $this->_unshiftContent_array(func_get_args());
48 elseif (is_array($arg))
49 $this->_unshiftContent_array($arg);
51 $this->_unshiftContent($arg);
54 function _unshiftContent_array ($array) {
55 foreach (array_reverse($array) as $item) {
57 $this->_unshiftContent_array($item);
59 $this->_unshiftContent($item);
63 function _unshiftContent ($item) {
64 if (get_class($item) == 'xmlcontent')
65 array_splice($this->_content, 0, 0, $item->_content);
67 array_unshift($this->_content, $item);
70 function getContent () {
71 return $this->_content;
74 function setContent ($arg /* , ... */) {
75 $this->_content = array();
76 $this->_pushContent_array(func_get_args());
79 function printXML () {
80 foreach ($this->_content as $item) {
81 if (is_object($item)) {
82 if (method_exists($item, 'printxml'))
84 elseif (method_exists($item, 'asxml'))
86 elseif (method_exists($item, 'asstring'))
87 echo $this->_quote($item->asString());
89 printf("==Object(%s)==", get_class($item));
92 echo $this->_quote((string) $item);
98 foreach ($this->_content as $item) {
99 if (is_object($item)) {
100 if (method_exists($item, 'asxml'))
101 $xml .= $item->asXML();
102 elseif (method_exists($item, 'asstring'))
103 $xml .= $this->_quote($item->asString());
105 $xml .= sprintf("==Object(%s)==", get_class($item));
108 $xml .= $this->_quote((string) $item);
115 foreach ($this->_content as $item) {
116 if (is_object($item)) {
117 if (method_exists($item, 'aspdf'))
118 $pdf .= $item->asPDF();
119 elseif (method_exists($item, 'asstring'))
120 $pdf .= $this->_quote($item->asString());
122 $pdf .= sprintf("==Object(%s)==", get_class($item));
125 $pdf .= $this->_quote((string) $item);
130 function asString () {
132 foreach ($this->_content as $item) {
133 if (is_object($item)) {
134 if (method_exists($item, 'asstring'))
135 $val .= $item->asString();
137 $val .= sprintf("==Object(%s)==", get_class($item));
140 $val .= (string) $item;
147 * See if element is empty.
149 * Empty means it has no content.
150 * @return bool True if empty.
152 function isEmpty () {
153 if (empty($this->_content))
155 foreach ($this->_content as $x) {
156 if (is_string($x) ? strlen($x) : !empty($x))
162 function _quote ($string) {
163 return htmlspecialchars($string);
170 * @param $tagname string Tag of html element.
172 class XmlElement extends XmlContent
174 function XmlElement ($tagname /* , $attr_or_content , ...*/) {
175 //FIXME: php5 incompatible
177 $this->_init(func_get_args());
180 function _init ($args) {
181 if (!is_array($args))
182 $args = func_get_args();
184 assert(count($args) >= 1);
185 //assert(is_string($args[0]));
186 $this->_tag = array_shift($args);
188 if ($args && is_array($args[0]))
189 $this->_attr = array_shift($args);
191 $this->_attr = array();
192 if ($args && $args[0] === false)
196 $this->setContent($args);
199 /** Methods only needed for XmlParser,
200 * to be fully compatible to perl Html::Element
202 function __destruct () {
203 foreach ($this->getChildren() as $node) {
208 unset($this->_content);
211 function getChildren () {
212 return $this->_children;
215 function hasChildren () {
216 return !empty($this->_children);
218 /* End XmlParser Methods
225 function setAttr ($attr, $value = false) {
226 if (is_array($attr)) {
227 assert($value === false);
228 foreach ($attr as $a => $v) {
229 $this->_attr[strtolower($a)] = $v;
230 //$this->set($a, $v);
235 assert(is_string($attr));
237 if ($value === false) {
238 unset($this->_attr[$attr]);
243 $this->_attr[$attr] = (string) $value;
246 if ($attr == 'class')
247 unset($this->_classes);
250 function getAttr ($attr) {
251 if ($attr == 'class')
252 $this->_setClasses();
254 if (isset($this->_attr[$attr]))
255 return $this->_attr[$attr];
260 function _getClasses() {
261 if (!isset($this->_classes)) {
262 $this->_classes = array();
263 if (isset($this->_attr['class'])) {
264 $classes = explode(' ', (string) $this->_attr['class']);
265 foreach ($classes as $class) {
266 $class = trim($class);
268 $this->_classes[$class] = $class;
272 return $this->_classes;
275 function _setClasses() {
276 if (isset($this->_classes)) {
278 $this->_attr['class'] = join(' ', $this->_classes);
280 unset($this->_attr['class']);
285 * Manipulate the elements CSS class membership.
287 * This adds or remove an elements membership
288 * in a give CSS class.
290 * @param $class string
292 * @param $in_class bool
293 * If true (the default) the element is added to class $class.
294 * If false, the element is removed from the class.
296 function setInClass($class, $in_class=true) {
297 $this->_getClasses();
298 $class = trim($class);
300 $this->_classes[$class] = $class;
302 unset($this->_classes[$class]);
306 * Is element in a given (CSS) class?
308 * This checks for the presence of a particular class in the
309 * elements 'class' attribute.
311 * @param $class string The class to check for.
312 * @return bool True if the element is a member of $class.
314 function inClass($class) {
315 $this->_parseClasses();
316 return isset($this->_classes[trim($class)]);
319 function startTag() {
320 $start = "<" . $this->_tag;
321 $this->_setClasses();
322 foreach ($this->_attr as $attr => $val) {
328 $qval = str_replace("\"", '"', $this->_quote((string)$val));
329 $start .= " $attr=\"$qval\"";
335 function emptyTag() {
336 return substr($this->startTag(), 0, -1) . "/>";
341 return "</$this->_tag>";
345 function printXML () {
346 if ($this->isEmpty())
347 echo $this->emptyTag();
349 echo $this->startTag();
350 // FIXME: The next two lines could be removed for efficiency
351 if (!$this->hasInlineContent())
353 XmlContent::printXML();
354 echo "</$this->_tag>";
356 if (!$this->isInlineElement())
361 if ($this->isEmpty()) {
362 $xml = $this->emptyTag();
365 $xml = $this->startTag();
366 // FIXME: The next two lines could be removed for efficiency
367 if (!$this->hasInlineContent())
369 $xml .= XmlContent::asXML();
370 $xml .= "</$this->_tag>";
372 if (!$this->isInlineElement())
378 * Can this element have inline content?
380 * This is a hack, but is probably the best one can do without
381 * knowledge of the DTD...
383 function hasInlineContent () {
385 if (empty($this->_content))
387 if (is_object($this->_content[0]))
393 * Is this element part of inline content?
395 * This is a hack, but is probably the best one can do without
396 * knowledge of the DTD...
398 function isInlineElement () {
405 function RawXml ($xml_text) {
406 $this->_xml = $xml_text;
409 function printXML () {
417 function isEmpty () {
418 return empty($this->_xml);
422 class FormattedText {
423 function FormattedText ($fs /* , ... */) {
425 $this->_init(func_get_args());
429 function _init ($args) {
430 $this->_fs = array_shift($args);
432 // PHP's sprintf doesn't support variable width specifiers,
433 // like sprintf("%*s", 10, "x"); --- so we won't either.
435 if (! preg_match_all('/(?<!%)%(\d+)\$/x', $this->_fs, $m)) {
436 $this->_args = $args;
439 // Format string has '%2$s' style argument reordering.
440 // PHP doesn't support this.
441 if (preg_match('/(?<!%)%[- ]?\d*[^- \d$]/x', $this->_fs)) // $fmt
442 // literal variable name substitution only to keep locale
443 // strings uncluttered
444 trigger_error(sprintf(_("Can't mix '%s' with '%s' type format strings"),
445 '%1\$s','%s'), E_USER_WARNING);
447 $this->_fs = preg_replace('/(?<!%)%\d+\$/x', '%', $this->_fs);
449 $this->_args = array();
450 foreach($m[1] as $argnum) {
451 if ($argnum < 1 || $argnum > count($args))
452 trigger_error(sprintf("%s: argument index out of range",
453 $argnum), E_USER_WARNING);
454 $this->_args[] = $args[$argnum - 1];
460 // Not all PHP's have vsprintf, so...
461 $args[] = XmlElement::_quote((string)$this->_fs);
462 foreach ($this->_args as $arg)
463 $args[] = AsXML($arg);
464 return call_user_func_array('sprintf', $args);
467 function printXML () {
468 // Not all PHP's have vsprintf, so...
469 $args[] = XmlElement::_quote((string)$this->_fs);
470 foreach ($this->_args as $arg)
471 $args[] = AsXML($arg);
472 call_user_func_array('printf', $args);
475 function asString() {
476 $args[] = $this->_fs;
477 foreach ($this->_args as $arg)
478 $args[] = AsString($arg);
479 return call_user_func_array('sprintf', $args);
483 function PrintXML ($val /* , ... */ ) {
484 if (func_num_args() > 1) {
485 foreach (func_get_args() as $arg)
488 elseif (is_object($val)) {
489 if (method_exists($val, 'printxml'))
491 elseif (method_exists($val, 'asxml')) {
494 elseif (method_exists($val, 'asstring'))
495 echo XmlContent::_quote($val->asString());
497 printf("==Object(%s)==", get_class($val));
499 elseif (is_array($val)) {
501 // Use XmlContent objects instead of arrays for collections of XmlElements.
502 trigger_error("Passing arrays to PrintXML() is deprecated: (" . AsXML($val, true) . ")",
508 echo (string)XmlContent::_quote((string)$val);
511 function AsXML ($val /* , ... */) {
514 if (func_num_args() > 1) {
516 foreach (func_get_args() as $arg)
520 elseif (is_object($val)) {
521 if (method_exists($val, 'asxml'))
522 return $val->asXML();
523 elseif (method_exists($val, 'asstring'))
524 return XmlContent::_quote($val->asString());
526 return sprintf("==Object(%s)==", get_class($val));
528 elseif (is_array($val)) {
530 // Use XmlContent objects instead of arrays for collections of XmlElements.
531 if (empty($nowarn)) {
533 trigger_error("Passing arrays to AsXML() is deprecated: (" . AsXML($val) . ")",
543 return XmlContent::_quote((string)$val);
546 function AsString ($val) {
547 if (func_num_args() > 1) {
549 foreach (func_get_args() as $arg)
550 $str .= AsString($arg);
553 elseif (is_object($val)) {
554 if (method_exists($val, 'asstring'))
555 return $val->asString();
557 return sprintf("==Object(%s)==", get_class($val));
559 elseif (is_array($val)) {
561 // Use XmlContent objects instead of arrays for collections of XmlElements.
562 trigger_error("Passing arrays to AsString() is deprecated", E_USER_NOTICE);
565 $str .= AsString($x);
569 return (string) $val;
573 function fmt ($fs /* , ... */) {
574 $s = new FormattedText(false);
576 $args = func_get_args();
577 $args[0] = _($args[0]);
582 // (c-file-style: "gnu")
587 // c-hanging-comment-ender-p: nil
588 // indent-tabs-mode: nil