1 <?php rcs_id('$Id: XmlElement.php,v 1.30 2004-06-19 12:33:25 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 if (!$string) return $string;
164 if (check_php_version(4,1) and isset($GLOBALS['charset']))
165 return htmlspecialchars($string,ENT_COMPAT,$GLOBALS['charset']);
167 return htmlspecialchars($string);
174 * @param $tagname string Tag of html element.
176 class XmlElement extends XmlContent
178 function XmlElement ($tagname /* , $attr_or_content , ...*/) {
179 //FIXME: php5 incompatible
181 $this->_init(func_get_args());
184 function _init ($args) {
185 if (!is_array($args))
186 $args = func_get_args();
188 assert(count($args) >= 1);
189 //assert(is_string($args[0]));
190 $this->_tag = array_shift($args);
192 if ($args && is_array($args[0]))
193 $this->_attr = array_shift($args);
195 $this->_attr = array();
196 if ($args && $args[0] === false)
200 $this->setContent($args);
203 /** Methods only needed for XmlParser,
204 * to be fully compatible to perl Html::Element
206 function __destruct () {
207 foreach ($this->getChildren() as $node) {
212 unset($this->_content);
215 function getChildren () {
216 return $this->_children;
219 function hasChildren () {
220 return !empty($this->_children);
222 /* End XmlParser Methods
229 function setAttr ($attr, $value = false) {
230 if (is_array($attr)) {
231 assert($value === false);
232 foreach ($attr as $a => $v) {
233 $this->_attr[strtolower($a)] = $v;
234 //$this->set($a, $v);
239 assert(is_string($attr));
241 if ($value === false) {
242 unset($this->_attr[$attr]);
247 $this->_attr[$attr] = (string) $value;
250 if ($attr == 'class')
251 unset($this->_classes);
254 function getAttr ($attr) {
255 if ($attr == 'class')
256 $this->_setClasses();
258 if (isset($this->_attr[$attr]))
259 return $this->_attr[$attr];
264 function _getClasses() {
265 if (!isset($this->_classes)) {
266 $this->_classes = array();
267 if (isset($this->_attr['class'])) {
268 $classes = explode(' ', (string) $this->_attr['class']);
269 foreach ($classes as $class) {
270 $class = trim($class);
272 $this->_classes[$class] = $class;
276 return $this->_classes;
279 function _setClasses() {
280 if (isset($this->_classes)) {
282 $this->_attr['class'] = join(' ', $this->_classes);
284 unset($this->_attr['class']);
289 * Manipulate the elements CSS class membership.
291 * This adds or remove an elements membership
292 * in a give CSS class.
294 * @param $class string
296 * @param $in_class bool
297 * If true (the default) the element is added to class $class.
298 * If false, the element is removed from the class.
300 function setInClass($class, $in_class=true) {
301 $this->_getClasses();
302 $class = trim($class);
304 $this->_classes[$class] = $class;
306 unset($this->_classes[$class]);
310 * Is element in a given (CSS) class?
312 * This checks for the presence of a particular class in the
313 * elements 'class' attribute.
315 * @param $class string The class to check for.
316 * @return bool True if the element is a member of $class.
318 function inClass($class) {
319 $this->_parseClasses();
320 return isset($this->_classes[trim($class)]);
323 function startTag() {
324 $start = "<" . $this->_tag;
325 $this->_setClasses();
326 foreach ($this->_attr as $attr => $val) {
332 $qval = str_replace("\"", '"', $this->_quote((string)$val));
333 $start .= " $attr=\"$qval\"";
339 function emptyTag() {
340 return substr($this->startTag(), 0, -1) . "/>";
345 return "</$this->_tag>";
349 function printXML () {
350 if ($this->isEmpty())
351 echo $this->emptyTag();
353 echo $this->startTag();
354 // FIXME: The next two lines could be removed for efficiency
355 if (!$this->hasInlineContent())
357 XmlContent::printXML();
358 echo "</$this->_tag>";
360 if (!$this->isInlineElement())
365 if ($this->isEmpty()) {
366 $xml = $this->emptyTag();
369 $xml = $this->startTag();
370 // FIXME: The next two lines could be removed for efficiency
371 if (!$this->hasInlineContent())
373 $xml .= XmlContent::asXML();
374 $xml .= "</$this->_tag>";
376 if (!$this->isInlineElement())
382 * Can this element have inline content?
384 * This is a hack, but is probably the best one can do without
385 * knowledge of the DTD...
387 function hasInlineContent () {
389 if (empty($this->_content))
391 if (is_object($this->_content[0]))
397 * Is this element part of inline content?
399 * This is a hack, but is probably the best one can do without
400 * knowledge of the DTD...
402 function isInlineElement () {
409 function RawXml ($xml_text) {
410 $this->_xml = $xml_text;
413 function printXML () {
421 function isEmpty () {
422 return empty($this->_xml);
426 class FormattedText {
427 function FormattedText ($fs /* , ... */) {
429 $this->_init(func_get_args());
433 function _init ($args) {
434 $this->_fs = array_shift($args);
436 // PHP's sprintf doesn't support variable width specifiers,
437 // like sprintf("%*s", 10, "x"); --- so we won't either.
439 if (! preg_match_all('/(?<!%)%(\d+)\$/x', $this->_fs, $m)) {
440 $this->_args = $args;
443 // Format string has '%2$s' style argument reordering.
444 // PHP doesn't support this.
445 if (preg_match('/(?<!%)%[- ]?\d*[^- \d$]/x', $this->_fs)) // $fmt
446 // literal variable name substitution only to keep locale
447 // strings uncluttered
448 trigger_error(sprintf(_("Can't mix '%s' with '%s' type format strings"),
449 '%1\$s','%s'), E_USER_WARNING);
451 $this->_fs = preg_replace('/(?<!%)%\d+\$/x', '%', $this->_fs);
453 $this->_args = array();
454 foreach($m[1] as $argnum) {
455 if ($argnum < 1 || $argnum > count($args))
456 trigger_error(sprintf("%s: argument index out of range",
457 $argnum), E_USER_WARNING);
458 $this->_args[] = $args[$argnum - 1];
464 // Not all PHP's have vsprintf, so...
465 $args[] = XmlElement::_quote((string)$this->_fs);
466 foreach ($this->_args as $arg)
467 $args[] = AsXML($arg);
468 return call_user_func_array('sprintf', $args);
471 function printXML () {
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 call_user_func_array('printf', $args);
479 function asString() {
480 $args[] = $this->_fs;
481 foreach ($this->_args as $arg)
482 $args[] = AsString($arg);
483 return call_user_func_array('sprintf', $args);
487 function PrintXML ($val /* , ... */ ) {
488 if (func_num_args() > 1) {
489 foreach (func_get_args() as $arg)
492 elseif (is_object($val)) {
493 if (method_exists($val, 'printxml'))
495 elseif (method_exists($val, 'asxml')) {
498 elseif (method_exists($val, 'asstring'))
499 echo XmlContent::_quote($val->asString());
501 printf("==Object(%s)==", get_class($val));
503 elseif (is_array($val)) {
505 // Use XmlContent objects instead of arrays for collections of XmlElements.
506 trigger_error("Passing arrays to PrintXML() is deprecated: (" . AsXML($val, true) . ")",
512 echo (string)XmlContent::_quote((string)$val);
515 function AsXML ($val /* , ... */) {
518 if (func_num_args() > 1) {
520 foreach (func_get_args() as $arg)
524 elseif (is_object($val)) {
525 if (method_exists($val, 'asxml'))
526 return $val->asXML();
527 elseif (method_exists($val, 'asstring'))
528 return XmlContent::_quote($val->asString());
530 return sprintf("==Object(%s)==", get_class($val));
532 elseif (is_array($val)) {
534 // Use XmlContent objects instead of arrays for collections of XmlElements.
535 if (empty($nowarn)) {
537 trigger_error("Passing arrays to AsXML() is deprecated: (" . AsXML($val) . ")",
547 return XmlContent::_quote((string)$val);
550 function AsString ($val) {
551 if (func_num_args() > 1) {
553 foreach (func_get_args() as $arg)
554 $str .= AsString($arg);
557 elseif (is_object($val)) {
558 if (method_exists($val, 'asstring'))
559 return $val->asString();
561 return sprintf("==Object(%s)==", get_class($val));
563 elseif (is_array($val)) {
565 // Use XmlContent objects instead of arrays for collections of XmlElements.
566 trigger_error("Passing arrays to AsString() is deprecated", E_USER_NOTICE);
569 $str .= AsString($x);
573 return (string) $val;
577 function fmt ($fs /* , ... */) {
578 $s = new FormattedText(false);
580 $args = func_get_args();
581 $args[0] = _($args[0]);
586 // (c-file-style: "gnu")
591 // c-hanging-comment-ender-p: nil
592 // indent-tabs-mode: nil