1 <?php rcs_id('$Id: XmlElement.php,v 1.18 2003-02-15 02:14:52 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>";
246 if (!$this->isInlineElement())
251 if ($this->isEmpty()) {
252 $xml = $this->emptyTag();
255 $xml = $this->startTag();
256 // FIXME: The next two lines could be removed for efficiency
257 if (!$this->hasInlineContent())
259 $xml .= XmlContent::asXML();
260 $xml .= "</$this->_tag>";
262 if (!$this->isInlineElement())
268 * Can this element have inline content?
270 * This is a hack, but is probably the best one can do without
271 * knowledge of the DTD...
273 function hasInlineContent () {
275 if (empty($this->_content))
277 if (is_object($this->_content[0]))
283 * Is this element part of inline content?
285 * This is a hack, but is probably the best one can do without
286 * knowledge of the DTD...
288 function isInlineElement () {
295 function RawXml ($xml_text) {
296 $this->_xml = $xml_text;
299 function printXML () {
307 function isEmpty () {
308 return empty($this->_xml);
312 class FormattedText {
313 function FormattedText ($fs /* , ... */) {
315 $this->_init(func_get_args());
319 function _init ($args) {
320 $this->_fs = array_shift($args);
322 // PHP's sprintf doesn't support variable width specifiers,
323 // like sprintf("%*s", 10, "x"); --- so we won't either.
325 if (! preg_match_all('/(?<!%)%(\d+)\$/x', $this->_fs, $m)) {
326 $this->_args = $args;
329 // Format string has '%2$s' style argument reordering.
330 // PHP doesn't support this.
331 if (preg_match('/(?<!%)%[- ]?\d*[^- \d$]/x', $this->_fs)) // $fmt
332 // literal variable name substitution only to keep locale
333 // strings uncluttered
334 trigger_error(sprintf(_("Can't mix '%s' with '%s' type format strings"),
335 '%1\$s','%s'), E_USER_WARNING);
337 $this->_fs = preg_replace('/(?<!%)%\d+\$/x', '%', $this->_fs);
339 $this->_args = array();
340 foreach($m[1] as $argnum) {
341 if ($argnum < 1 || $argnum > count($args))
342 trigger_error(sprintf("%s: argument index out of range",
343 $argnum), E_USER_WARNING);
344 $this->_args[] = $args[$argnum - 1];
350 // Not all PHP's have vsprintf, so...
351 $args[] = XmlElement::_quote($this->_fs);
352 foreach ($this->_args as $arg)
353 $args[] = AsXML($arg);
354 return call_user_func_array('sprintf', $args);
357 function printXML () {
358 // Not all PHP's have vsprintf, so...
359 $args[] = XmlElement::_quote($this->_fs);
360 foreach ($this->_args as $arg)
361 $args[] = AsXML($arg);
362 call_user_func_array('printf', $args);
365 function asString() {
366 $args[] = $this->_fs;
367 foreach ($this->_args as $arg)
368 $args[] = AsString($arg);
369 return call_user_func_array('sprintf', $args);
373 function PrintXML ($val /* , ... */ ) {
374 if (func_num_args() > 1) {
375 foreach (func_get_args() as $arg)
378 elseif (is_object($val)) {
379 if (method_exists($val, 'printxml'))
381 elseif (method_exists($val, 'asxml')) {
384 elseif (method_exists($val, 'asstring'))
385 echo XmlContent::_quote($val->asString());
387 printf("==Object(%s)==", get_class($val));
389 elseif (is_array($val)) {
391 // Use XmlContent objects instead of arrays for collections of XmlElements.
392 trigger_error("Passing arrays to PrintXML() is deprecated: (" . AsXML($val, true) . ")",
398 echo (string)XmlContent::_quote($val);
401 function AsXML ($val /* , ... */) {
404 if (func_num_args() > 1) {
406 foreach (func_get_args() as $arg)
410 elseif (is_object($val)) {
411 if (method_exists($val, 'asxml'))
412 return $val->asXML();
413 elseif (method_exists($val, 'asstring'))
414 return XmlContent::_quote($val->asString());
416 return sprintf("==Object(%s)==", get_class($val));
418 elseif (is_array($val)) {
420 // Use XmlContent objects instead of arrays for collections of XmlElements.
421 if (empty($nowarn)) {
423 trigger_error("Passing arrays to AsXML() is deprecated: (" . AsXML($val) . ")",
433 return XmlContent::_quote((string)$val);
436 function AsString ($val) {
437 if (func_num_args() > 1) {
439 foreach (func_get_args() as $arg)
440 $str .= AsString($arg);
443 elseif (is_object($val)) {
444 if (method_exists($val, 'asstring'))
445 return $val->asString();
447 return sprintf("==Object(%s)==", get_class($val));
449 elseif (is_array($val)) {
451 // Use XmlContent objects instead of arrays for collections of XmlElements.
452 trigger_error("Passing arrays to AsString() is deprecated", E_USER_NOTICE);
455 $str .= AsString($x);
459 return (string) $val;
463 function fmt ($fs /* , ... */) {
464 $s = new FormattedText(false);
466 $args = func_get_args();
467 $args[0] = _($args[0]);
472 // (c-file-style: "gnu")
477 // c-hanging-comment-ender-p: nil
478 // indent-tabs-mode: nil