1 <?php rcs_id('$Id: XmlElement.php,v 1.27 2004-04-19 18:27:45 rurban Exp $');
3 * Code for writing XML.
4 * @author: Jeff Dairiki
6 * FIXME: This code is not (yet) php5 compatible.
10 * A sequence of (zero or more) XmlElements (possibly interspersed with
11 * plain strings (CDATA).
15 function XmlContent (/* ... */) {
16 $this->_content = array();
17 $this->_pushContent_array(func_get_args());
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);
26 $this->_pushContent($arg);
29 function _pushContent_array ($array) {
30 foreach ($array as $item) {
32 $this->_pushContent_array($item);
34 $this->_pushContent($item);
38 function _pushContent ($item) {
39 if (get_class($item) == 'xmlcontent')
40 array_splice($this->_content, count($this->_content), 0,
43 $this->_content[] = $item;
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);
52 $this->_unshiftContent($arg);
55 function _unshiftContent_array ($array) {
56 foreach (array_reverse($array) as $item) {
58 $this->_unshiftContent_array($item);
60 $this->_unshiftContent($item);
64 function _unshiftContent ($item) {
65 if (get_class($item) == 'xmlcontent')
66 array_splice($this->_content, 0, 0, $item->_content);
68 array_unshift($this->_content, $item);
71 function getContent () {
72 return $this->_content;
75 function setContent ($arg /* , ... */) {
76 $this->_content = array();
77 $this->_pushContent_array(func_get_args());
80 function printXML () {
81 foreach ($this->_content as $item) {
82 if (is_object($item)) {
83 if (method_exists($item, 'printxml'))
85 elseif (method_exists($item, 'asxml'))
87 elseif (method_exists($item, 'asstring'))
88 echo $this->_quote($item->asString());
90 printf("==Object(%s)==", get_class($item));
93 echo $this->_quote((string) $item);
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());
106 $xml .= sprintf("==Object(%s)==", get_class($item));
109 $xml .= $this->_quote((string) $item);
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());
123 $pdf .= sprintf("==Object(%s)==", get_class($item));
126 $pdf .= $this->_quote((string) $item);
131 function asString () {
133 foreach ($this->_content as $item) {
134 if (is_object($item)) {
135 if (method_exists($item, 'asstring'))
136 $val .= $item->asString();
138 $val .= sprintf("==Object(%s)==", get_class($item));
141 $val .= (string) $item;
148 * See if element is empty.
150 * Empty means it has no content.
151 * @return bool True if empty.
153 function isEmpty () {
154 if (empty($this->_content))
156 foreach ($this->_content as $x) {
157 if (is_string($x) ? strlen($x) : !empty($x))
163 function _quote ($string) {
164 return htmlspecialchars($string);
171 * @param $tagname string Tag of html element.
173 class XmlElement extends XmlContent
175 function XmlElement ($tagname /* , $attr_or_content , ...*/) {
176 //FIXME: php5 incompatible
178 $this->_init(func_get_args());
181 function _init ($args) {
182 if (!is_array($args))
183 $args = func_get_args();
185 assert(count($args) >= 1);
186 //assert(is_string($args[0]));
187 $this->_tag = array_shift($args);
189 if ($args && is_array($args[0]))
190 $this->_attr = array_shift($args);
192 $this->_attr = array();
193 if ($args && $args[0] === false)
197 $this->setContent($args);
204 function setAttr ($attr, $value = false) {
205 if (is_array($attr)) {
206 assert($value === false);
207 foreach ($attr as $a => $v)
212 assert(is_string($attr));
214 if ($value === false) {
215 unset($this->_attr[$attr]);
220 $this->_attr[$attr] = (string) $value;
223 if ($attr == 'class')
224 unset($this->_classes);
227 function getAttr ($attr) {
228 if ($attr == 'class')
229 $this->_setClasses();
231 if (isset($this->_attr[$attr]))
232 return $this->_attr[$attr];
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);
245 $this->_classes[$class] = $class;
249 return $this->_classes;
252 function _setClasses() {
253 if (isset($this->_classes)) {
255 $this->_attr['class'] = join(' ', $this->_classes);
257 unset($this->_attr['class']);
262 * Manipulate the elements CSS class membership.
264 * This adds or remove an elements membership
265 * in a give CSS class.
267 * @param $class string
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.
273 function setInClass($class, $in_class=true) {
274 $this->_getClasses();
275 $class = trim($class);
277 $this->_classes[$class] = $class;
279 unset($this->_classes[$class]);
283 * Is element in a given (CSS) class?
285 * This checks for the presence of a particular class in the
286 * elements 'class' attribute.
288 * @param $class string The class to check for.
289 * @return bool True if the element is a member of $class.
291 function inClass($class) {
292 $this->_parseClasses();
293 return isset($this->_classes[trim($class)]);
296 function startTag() {
297 $start = "<" . $this->_tag;
298 $this->_setClasses();
299 foreach ($this->_attr as $attr => $val) {
305 $qval = str_replace("\"", '"', $this->_quote((string)$val));
306 $start .= " $attr=\"$qval\"";
312 function emptyTag() {
313 return substr($this->startTag(), 0, -1) . "/>";
318 return "</$this->_tag>";
322 function printXML () {
323 if ($this->isEmpty())
324 echo $this->emptyTag();
326 echo $this->startTag();
327 // FIXME: The next two lines could be removed for efficiency
328 if (!$this->hasInlineContent())
330 XmlContent::printXML();
331 echo "</$this->_tag>";
333 if (!$this->isInlineElement())
338 if ($this->isEmpty()) {
339 $xml = $this->emptyTag();
342 $xml = $this->startTag();
343 // FIXME: The next two lines could be removed for efficiency
344 if (!$this->hasInlineContent())
346 $xml .= XmlContent::asXML();
347 $xml .= "</$this->_tag>";
349 if (!$this->isInlineElement())
355 * Can this element have inline content?
357 * This is a hack, but is probably the best one can do without
358 * knowledge of the DTD...
360 function hasInlineContent () {
362 if (empty($this->_content))
364 if (is_object($this->_content[0]))
370 * Is this element part of inline content?
372 * This is a hack, but is probably the best one can do without
373 * knowledge of the DTD...
375 function isInlineElement () {
382 function RawXml ($xml_text) {
383 $this->_xml = $xml_text;
386 function printXML () {
394 function isEmpty () {
395 return empty($this->_xml);
399 class FormattedText {
400 function FormattedText ($fs /* , ... */) {
402 $this->_init(func_get_args());
406 function _init ($args) {
407 $this->_fs = array_shift($args);
409 // PHP's sprintf doesn't support variable width specifiers,
410 // like sprintf("%*s", 10, "x"); --- so we won't either.
412 if (! preg_match_all('/(?<!%)%(\d+)\$/x', $this->_fs, $m)) {
413 $this->_args = $args;
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);
424 $this->_fs = preg_replace('/(?<!%)%\d+\$/x', '%', $this->_fs);
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];
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);
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);
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);
460 function PrintXML ($val /* , ... */ ) {
461 if (func_num_args() > 1) {
462 foreach (func_get_args() as $arg)
465 elseif (is_object($val)) {
466 if (method_exists($val, 'printxml'))
468 elseif (method_exists($val, 'asxml')) {
471 elseif (method_exists($val, 'asstring'))
472 echo XmlContent::_quote($val->asString());
474 printf("==Object(%s)==", get_class($val));
476 elseif (is_array($val)) {
478 // Use XmlContent objects instead of arrays for collections of XmlElements.
479 trigger_error("Passing arrays to PrintXML() is deprecated: (" . AsXML($val, true) . ")",
485 echo (string)XmlContent::_quote((string)$val);
488 function AsXML ($val /* , ... */) {
491 if (func_num_args() > 1) {
493 foreach (func_get_args() as $arg)
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());
503 return sprintf("==Object(%s)==", get_class($val));
505 elseif (is_array($val)) {
507 // Use XmlContent objects instead of arrays for collections of XmlElements.
508 if (empty($nowarn)) {
510 trigger_error("Passing arrays to AsXML() is deprecated: (" . AsXML($val) . ")",
520 return XmlContent::_quote((string)$val);
523 function AsString ($val) {
524 if (func_num_args() > 1) {
526 foreach (func_get_args() as $arg)
527 $str .= AsString($arg);
530 elseif (is_object($val)) {
531 if (method_exists($val, 'asstring'))
532 return $val->asString();
534 return sprintf("==Object(%s)==", get_class($val));
536 elseif (is_array($val)) {
538 // Use XmlContent objects instead of arrays for collections of XmlElements.
539 trigger_error("Passing arrays to AsString() is deprecated", E_USER_NOTICE);
542 $str .= AsString($x);
546 return (string) $val;
550 function fmt ($fs /* , ... */) {
551 $s = new FormattedText(false);
553 $args = func_get_args();
554 $args[0] = _($args[0]);
559 // (c-file-style: "gnu")
564 // c-hanging-comment-ender-p: nil
565 // indent-tabs-mode: nil