1 <?php rcs_id('$Id: XmlElement.php,v 1.16 2002-02-07 00:26:08 dairiki Exp $');
3 * Code for writing XML.
7 * A sequence of (zero or more) XmlElements (possibly interspersed with
8 * plain strings (CDATA).
12 function XmlContent (/* ... */) {
13 $this->_content = array();
14 $this->_pushContent_array(func_get_args());
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);
23 $this->_pushContent($arg);
26 function _pushContent_array ($array) {
27 foreach ($array as $item) {
29 $this->_pushContent_array($item);
31 $this->_pushContent($item);
35 function _pushContent ($item) {
36 if (get_class($item) == 'xmlcontent')
37 array_splice($this->_content, count($this->_content), 0,
40 $this->_content[] = $item;
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);
49 $this->_unshiftContent($arg);
52 function _unshiftContent_array ($array) {
53 foreach (array_reverse($array) as $item) {
55 $this->_unshiftContent_array($item);
57 $this->_unshiftContent($item);
61 function _unshiftContent ($item) {
62 if (get_class($item) == 'xmlcontent')
63 array_splice($this->_content, 0, 0, $item->_content);
65 array_unshift($this->_content, $item);
68 function getContent () {
69 return $this->_content;
72 function setContent ($arg /* , ... */) {
73 $this->_content = array();
74 $this->_pushContent_array(func_get_args());
77 function printXML () {
78 foreach ($this->_content as $item) {
79 if (is_object($item)) {
80 if (method_exists($item, 'printxml'))
82 elseif (method_exists($item, 'asxml'))
84 elseif (method_exists($item, 'asstring'))
85 echo $this->_quote($item->asString());
87 printf("==Object(%s)==", get_class($item));
90 echo $this->_quote((string) $item);
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());
104 $xml .= sprintf("==Object(%s)==", get_class($item));
107 $xml .= $this->_quote((string) $item);
112 function asString () {
114 foreach ($this->_content as $item) {
115 if (is_object($item)) {
116 if (method_exists($item, 'asstring'))
117 $val .= $item->asString();
119 $val .= sprintf("==Object(%s)==", get_class($item));
122 $val .= (string) $item;
129 * See if element is empty.
131 * Empty means it has no content.
132 * @return bool True if empty.
134 function isEmpty () {
135 if (empty($this->_content))
137 foreach ($this->_content as $x) {
144 function _quote ($string) {
145 return str_replace('<', '<',
146 str_replace('>', '>',
147 str_replace('&', '&', $string)));
154 * @param $tagname string Tag of html element.
156 class XmlElement extends XmlContent
158 function XmlElement ($tagname /* , $attr_or_content , ...*/) {
160 $this->_init(func_get_args());
163 function _init ($args) {
164 if (!is_array($args))
165 $args = func_get_args();
167 assert(count($args) >= 1);
168 //assert(is_string($args[0]));
169 $this->_tag = array_shift($args);
171 if ($args && is_array($args[0]))
172 $this->_attr = array_shift($args);
174 $this->_attr = array();
175 if ($args && $args[0] === false)
179 $this->setContent($args);
186 function setAttr ($attr, $value = false) {
187 if (is_array($attr)) {
188 assert($value === false);
189 foreach ($attr as $a => $v)
194 assert(is_string($attr));
195 if ($value === false) {
196 unset($this->_attr[$attr]);
200 $this->_attr[$attr] = (string) $value;
203 function getAttr ($attr) {
204 if (isset($this->_attr[$attr]))
205 return $this->_attr[$attr];
210 function startTag() {
211 $start = "<" . $this->_tag;
212 foreach ($this->_attr as $attr => $val) {
218 $qval = str_replace("\"", '"', $this->_quote($val));
219 $start .= " $attr=\"$qval\"";
225 function emptyTag() {
226 return substr($this->startTag(), 0, -1) . "/>";
231 return "</$this->_tag>";
235 function printXML () {
236 if ($this->isEmpty())
237 echo $this->emptyTag();
239 echo $this->startTag();
240 // FIXME: The next two lines could be removed for efficiency
241 if (!$this->hasInlineContent())
243 XmlContent::printXML();
244 echo "</$this->_tag>";
245 if (!$this->isInlineElement())
251 if ($this->isEmpty())
252 return $this->emptyTag();
254 $xml = $this->startTag();
255 // FIXME: The next two lines could be removed for efficiency
256 if (!$this->hasInlineContent())
258 $xml .= XmlContent::asXML();
259 $xml .= "</$this->_tag>";
260 if (!$this->isInlineElement())
267 * Can this element have inline content?
269 * This is a hack, but is probably the best one can do without
270 * knowledge of the DTD...
272 function hasInlineContent () {
274 if (empty($this->_content))
276 if (is_object($this->_content[0]))
282 * Is this element part of inline content?
284 * This is a hack, but is probably the best one can do without
285 * knowledge of the DTD...
287 function isInlineElement () {
294 function RawXml ($xml_text) {
295 $this->_xml = $xml_text;
298 function printXML () {
306 function isEmpty () {
307 return empty($this->_xml);
311 class FormattedText {
312 function FormattedText ($fs /* , ... */) {
314 $this->_init(func_get_args());
318 function _init ($args) {
319 $this->_fs = array_shift($args);
321 // PHP's sprintf doesn't support variable width specifiers,
322 // like sprintf("%*s", 10, "x"); --- so we won't either.
324 if (! preg_match_all('/(?<!%)%(\d+)\$/x', $this->_fs, $m)) {
325 $this->_args = $args;
328 // Format string has '%2$s' style argument reordering.
329 // PHP doesn't support this.
330 if (preg_match('/(?<!%)%[- ]?\d*[^- \d$]/x', $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);
336 $this->_fs = preg_replace('/(?<!%)%\d+\$/x', '%', $this->_fs);
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];
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);
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);
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);
372 function PrintXML ($val /* , ... */ ) {
373 if (func_num_args() > 1) {
374 foreach (func_get_args() as $arg)
377 elseif (is_object($val)) {
378 if (method_exists($val, 'printxml'))
380 elseif (method_exists($val, 'asxml')) {
383 elseif (method_exists($val, 'asstring'))
384 echo XmlContent::_quote($val->asString());
386 printf("==Object(%s)==", get_class($val));
388 elseif (is_array($val)) {
390 // Use XmlContent objects instead of arrays for collections of XmlElements.
391 trigger_error("Passing arrays to PrintXML() is deprecated: (" . AsXML($val, true) . ")",
397 echo (string)XmlContent::_quote($val);
400 function AsXML ($val /* , ... */) {
403 if (func_num_args() > 1) {
405 foreach (func_get_args() as $arg)
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());
415 return sprintf("==Object(%s)==", get_class($val));
417 elseif (is_array($val)) {
419 // Use XmlContent objects instead of arrays for collections of XmlElements.
420 if (empty($nowarn)) {
422 trigger_error("Passing arrays to AsXML() is deprecated: (" . AsXML($val) . ")",
432 return XmlContent::_quote((string)$val);
435 function AsString ($val) {
436 if (func_num_args() > 1) {
438 foreach (func_get_args() as $arg)
439 $str .= AsString($arg);
442 elseif (is_object($val)) {
443 if (method_exists($val, 'asstring'))
444 return $val->asString();
446 return sprintf("==Object(%s)==", get_class($val));
448 elseif (is_array($val)) {
450 // Use XmlContent objects instead of arrays for collections of XmlElements.
451 trigger_error("Passing arrays to AsString() is deprecated", E_USER_NOTICE);
454 $str .= AsString($x);
458 return (string) $val;
462 function fmt ($fs /* , ... */) {
463 $s = new FormattedText(false);
465 $args = func_get_args();
466 $args[0] = _($args[0]);
471 // (c-file-style: "gnu")
476 // c-hanging-comment-ender-p: nil
477 // indent-tabs-mode: nil