PageRenderTime 60ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

/gforge/plugins/wiki/www/lib/XmlElement.php

https://github.com/neymanna/fusionforge
PHP | 645 lines | 554 code | 36 blank | 55 comment | 45 complexity | 48870bb3e35783784a9123ea5a013880 MD5 | raw file
Possible License(s): GPL-2.0, MPL-2.0-no-copyleft-exception
  1. <?php rcs_id('$Id: XmlElement.php,v 1.38 2005/10/10 19:36:09 rurban Exp $');
  2. /**
  3. * Code for writing XML.
  4. * @package Markup
  5. * @author: Jeff Dairiki,
  6. * Reini Urban (php5 tricks)
  7. *
  8. * WARNING: This module is very php5 sensitive.
  9. * Fixed for 1.3.9 and 1.3.11.
  10. * With allow_call_time_pass_reference clean fixes.
  11. */
  12. /**
  13. * A sequence of (zero or more) XmlElements (possibly interspersed with
  14. * plain strings (CDATA).
  15. */
  16. class XmlContent
  17. {
  18. function XmlContent (/* ... */) {
  19. $this->_content = array();
  20. $this->_pushContent_array(func_get_args());
  21. }
  22. function pushContent ($arg /*, ...*/) {
  23. if (func_num_args() > 1)
  24. $this->_pushContent_array(func_get_args());
  25. elseif (is_array($arg))
  26. $this->_pushContent_array($arg);
  27. else
  28. $this->_pushContent($arg);
  29. }
  30. function _pushContent_array ($array) {
  31. foreach ($array as $item) {
  32. if (is_array($item))
  33. $this->_pushContent_array($item);
  34. else
  35. $this->_pushContent($item);
  36. }
  37. }
  38. function _pushContent ($item) {
  39. if (strtolower(get_class($item)) == 'xmlcontent')
  40. array_splice($this->_content, count($this->_content), 0,
  41. $item->_content);
  42. else
  43. $this->_content[] = $item;
  44. }
  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);
  50. else
  51. $this->_unshiftContent($arg);
  52. }
  53. function _unshiftContent_array ($array) {
  54. foreach (array_reverse($array) as $item) {
  55. if (is_array($item))
  56. $this->_unshiftContent_array($item);
  57. else
  58. $this->_unshiftContent($item);
  59. }
  60. }
  61. function _unshiftContent ($item) {
  62. if (strtolower(get_class($item)) == 'xmlcontent')
  63. array_splice($this->_content, 0, 0, $item->_content);
  64. else
  65. array_unshift($this->_content, $item);
  66. }
  67. function getContent () {
  68. return $this->_content;
  69. }
  70. function setContent ($arg /* , ... */) {
  71. $this->_content = array();
  72. $this->_pushContent_array(func_get_args());
  73. }
  74. function printXML () {
  75. foreach ($this->_content as $item) {
  76. if (is_object($item)) {
  77. if (method_exists($item, 'printXML'))
  78. $item->printXML();
  79. elseif (method_exists($item, 'asXML'))
  80. echo $item->asXML();
  81. elseif (method_exists($item, 'asString'))
  82. echo $this->_quote($item->asString());
  83. else
  84. printf("==Object(%s)==", get_class($item));
  85. }
  86. else
  87. echo $this->_quote((string) $item);
  88. }
  89. }
  90. function asXML () {
  91. $xml = '';
  92. foreach ($this->_content as $item) {
  93. if (is_object($item)) {
  94. if (method_exists($item, 'asXML'))
  95. $xml .= $item->asXML();
  96. elseif (method_exists($item, 'asString'))
  97. $xml .= $this->_quote($item->asString());
  98. else
  99. $xml .= sprintf("==Object(%s)==", get_class($item));
  100. }
  101. else
  102. $xml .= $this->_quote((string) $item);
  103. }
  104. return $xml;
  105. }
  106. function asPDF () {
  107. $pdf = '';
  108. foreach ($this->_content as $item) {
  109. if (is_object($item)) {
  110. if (method_exists($item, 'asPDF'))
  111. $pdf .= $item->asPDF();
  112. elseif (method_exists($item, 'asString'))
  113. $pdf .= $this->_quote($item->asString());
  114. else
  115. $pdf .= sprintf("==Object(%s)==", get_class($item));
  116. }
  117. else
  118. $pdf .= $this->_quote((string) $item);
  119. }
  120. return $pdf;
  121. }
  122. function asString () {
  123. $val = '';
  124. foreach ($this->_content as $item) {
  125. if (is_object($item)) {
  126. if (method_exists($item, 'asString'))
  127. $val .= $item->asString();
  128. else
  129. $val .= sprintf("==Object(%s)==", get_class($item));
  130. }
  131. else
  132. $val .= (string) $item;
  133. }
  134. return trim($val);
  135. }
  136. /**
  137. * See if element is empty.
  138. *
  139. * Empty means it has no content.
  140. * @return bool True if empty.
  141. */
  142. function isEmpty () {
  143. if (empty($this->_content))
  144. return true;
  145. foreach ($this->_content as $x) {
  146. if (is_string($x) ? strlen($x) : !empty($x))
  147. return false;
  148. }
  149. return true;
  150. }
  151. function _quote ($string) {
  152. if (!$string) return $string;
  153. if (check_php_version(4,1) and isset($GLOBALS['charset']))
  154. return htmlspecialchars($string, ENT_COMPAT, $GLOBALS['charset']);
  155. else
  156. return htmlspecialchars($string);
  157. }
  158. };
  159. /**
  160. * An XML element.
  161. *
  162. * @param $tagname string Tag of html element.
  163. */
  164. class XmlElement extends XmlContent
  165. {
  166. function XmlElement ($tagname /* , $attr_or_content , ...*/) {
  167. //FIXME: php5 incompatible
  168. $this->XmlContent();
  169. $this->_init(func_get_args());
  170. }
  171. function _init ($args) {
  172. if (!is_array($args))
  173. $args = func_get_args();
  174. assert(count($args) >= 1);
  175. //assert(is_string($args[0]));
  176. $this->_tag = array_shift($args);
  177. if ($args && is_array($args[0]))
  178. $this->_attr = array_shift($args);
  179. else {
  180. $this->_attr = array();
  181. if ($args && $args[0] === false)
  182. array_shift($args);
  183. }
  184. $this->setContent($args);
  185. }
  186. /** Methods only needed for XmlParser,
  187. * to be fully compatible to perl Html::Element
  188. */
  189. // doesn't yet work with php5 as __destruct()
  190. function _destruct () {
  191. if ($this->hasChildren()) {
  192. foreach ($this->getChildren() as $node) {
  193. $node->_destruct();
  194. }
  195. }
  196. unset($this->_tag);
  197. unset($this->_attr);
  198. unset($this->_content);
  199. }
  200. function getChildren () {
  201. return $this->_children;
  202. }
  203. function hasChildren () {
  204. return !empty($this->_children);
  205. }
  206. /* End XmlParser Methods
  207. */
  208. function getTag () {
  209. return $this->_tag;
  210. }
  211. function setAttr ($attr, $value = false) {
  212. if (is_array($attr)) {
  213. assert($value === false);
  214. foreach ($attr as $a => $v) {
  215. $this->_attr[strtolower($a)] = $v;
  216. //$this->set($a, $v);
  217. }
  218. return;
  219. }
  220. assert(is_string($attr));
  221. if ($value === false) {
  222. unset($this->_attr[$attr]);
  223. }
  224. else {
  225. if (is_bool($value))
  226. $value = $attr;
  227. $this->_attr[$attr] = (string) $value;
  228. }
  229. if ($attr == 'class')
  230. unset($this->_classes);
  231. }
  232. function getAttr ($attr) {
  233. if ($attr == 'class')
  234. $this->_setClasses();
  235. if (isset($this->_attr[strtolower($attr)]))
  236. return $this->_attr[strtolower($attr)];
  237. else
  238. return false;
  239. }
  240. function _getClasses() {
  241. if (!isset($this->_classes)) {
  242. $this->_classes = array();
  243. if (isset($this->_attr['class'])) {
  244. $classes = explode(' ', (string) $this->_attr['class']);
  245. foreach ($classes as $class) {
  246. $class = trim($class);
  247. if ($class)
  248. $this->_classes[$class] = $class;
  249. }
  250. }
  251. }
  252. return $this->_classes;
  253. }
  254. function _setClasses() {
  255. if (isset($this->_classes)) {
  256. if ($this->_classes)
  257. $this->_attr['class'] = join(' ', $this->_classes);
  258. else
  259. unset($this->_attr['class']);
  260. }
  261. }
  262. /**
  263. * Manipulate the elements CSS class membership.
  264. *
  265. * This adds or remove an elements membership
  266. * in a give CSS class.
  267. *
  268. * @param $class string
  269. *
  270. * @param $in_class bool
  271. * If true (the default) the element is added to class $class.
  272. * If false, the element is removed from the class.
  273. */
  274. function setInClass($class, $in_class=true) {
  275. $this->_getClasses();
  276. $class = trim($class);
  277. if ($in_class)
  278. $this->_classes[$class] = $class;
  279. else
  280. unset($this->_classes[$class]);
  281. }
  282. /**
  283. * Is element in a given (CSS) class?
  284. *
  285. * This checks for the presence of a particular class in the
  286. * elements 'class' attribute.
  287. *
  288. * @param $class string The class to check for.
  289. * @return bool True if the element is a member of $class.
  290. */
  291. function inClass($class) {
  292. $this->_parseClasses();
  293. return isset($this->_classes[trim($class)]);
  294. }
  295. function startTag() {
  296. $start = "<" . $this->_tag;
  297. $this->_setClasses();
  298. foreach ($this->_attr as $attr => $val) {
  299. if (is_bool($val)) {
  300. if (!$val)
  301. continue;
  302. $val = $attr;
  303. }
  304. $qval = str_replace("\"", '&quot;', $this->_quote((string)$val));
  305. $start .= " $attr=\"$qval\"";
  306. }
  307. $start .= ">";
  308. return $start;
  309. }
  310. function emptyTag() {
  311. return substr($this->startTag(), 0, -1) . "/>";
  312. }
  313. function endTag() {
  314. return "</$this->_tag>";
  315. }
  316. function printXML () {
  317. if ($this->isEmpty())
  318. echo $this->emptyTag();
  319. else {
  320. echo $this->startTag();
  321. // FIXME: The next two lines could be removed for efficiency
  322. if (!$this->hasInlineContent())
  323. echo "\n";
  324. XmlContent::printXML();
  325. echo "</$this->_tag>";
  326. }
  327. if (!$this->isInlineElement())
  328. echo "\n";
  329. }
  330. function asXML () {
  331. if ($this->isEmpty()) {
  332. $xml = $this->emptyTag();
  333. }
  334. else {
  335. $xml = $this->startTag();
  336. // FIXME: The next two lines could be removed for efficiency
  337. if (!$this->hasInlineContent())
  338. $xml .= "\n";
  339. $xml .= XmlContent::asXML();
  340. $xml .= "</$this->_tag>";
  341. }
  342. if (!$this->isInlineElement())
  343. $xml .= "\n";
  344. return $xml;
  345. }
  346. /**
  347. * Can this element have inline content?
  348. *
  349. * This is a hack, but is probably the best one can do without
  350. * knowledge of the DTD...
  351. */
  352. function hasInlineContent () {
  353. // This is a hack.
  354. if (empty($this->_content))
  355. return true;
  356. if (is_object($this->_content[0]))
  357. return false;
  358. return true;
  359. }
  360. /**
  361. * Is this element part of inline content?
  362. *
  363. * This is a hack, but is probably the best one can do without
  364. * knowledge of the DTD...
  365. */
  366. function isInlineElement () {
  367. return false;
  368. }
  369. };
  370. class RawXml {
  371. function RawXml ($xml_text) {
  372. $this->_xml = $xml_text;
  373. }
  374. function printXML () {
  375. echo $this->_xml;
  376. }
  377. function asXML () {
  378. return $this->_xml;
  379. }
  380. function isEmpty () {
  381. return empty($this->_xml);
  382. }
  383. }
  384. class FormattedText {
  385. function FormattedText ($fs /* , ... */) {
  386. if ($fs !== false) {
  387. $this->_init(func_get_args());
  388. }
  389. }
  390. function _init ($args) {
  391. $this->_fs = array_shift($args);
  392. // PHP's sprintf doesn't support variable width specifiers,
  393. // like sprintf("%*s", 10, "x"); --- so we won't either.
  394. $m = array();
  395. if (! preg_match_all('/(?<!%)%(\d+)\$/x', $this->_fs, $m)) {
  396. $this->_args = $args;
  397. }
  398. else {
  399. // Format string has '%2$s' style argument reordering.
  400. // PHP doesn't support this.
  401. if (preg_match('/(?<!%)%[- ]?\d*[^- \d$]/x', $this->_fs)) // $fmt
  402. // literal variable name substitution only to keep locale
  403. // strings uncluttered
  404. trigger_error(sprintf(_("Can't mix '%s' with '%s' type format strings"),
  405. '%1\$s','%s'), E_USER_WARNING);
  406. $this->_fs = preg_replace('/(?<!%)%\d+\$/x', '%', $this->_fs);
  407. $this->_args = array();
  408. foreach($m[1] as $argnum) {
  409. if ($argnum < 1 || $argnum > count($args))
  410. trigger_error(sprintf("%s: argument index out of range",
  411. $argnum), E_USER_WARNING);
  412. $this->_args[] = $args[$argnum - 1];
  413. }
  414. }
  415. }
  416. function asXML () {
  417. // Not all PHP's have vsprintf, so...
  418. $args[] = XmlElement::_quote((string)$this->_fs);
  419. foreach ($this->_args as $arg)
  420. $args[] = AsXML($arg);
  421. return call_user_func_array('sprintf', $args);
  422. }
  423. function printXML () {
  424. // Not all PHP's have vsprintf, so...
  425. $args[] = XmlElement::_quote((string)$this->_fs);
  426. foreach ($this->_args as $arg)
  427. $args[] = AsXML($arg);
  428. call_user_func_array('printf', $args);
  429. }
  430. function asString() {
  431. $args[] = $this->_fs;
  432. foreach ($this->_args as $arg)
  433. $args[] = AsString($arg);
  434. return call_user_func_array('sprintf', $args);
  435. }
  436. }
  437. /**
  438. * PHP5 compatibility
  439. * Error[2048]: Non-static method XmlContent::_quote() should not be called statically
  440. */
  441. function XmlContent_quote ($string) {
  442. if (!$string) return $string;
  443. if (check_php_version(4,1) and isset($GLOBALS['charset']))
  444. return htmlspecialchars($string, ENT_COMPAT, $GLOBALS['charset']);
  445. else
  446. return htmlspecialchars($string);
  447. }
  448. function PrintXML ($val /* , ... */ ) {
  449. if (func_num_args() > 1) {
  450. foreach (func_get_args() as $arg)
  451. PrintXML($arg);
  452. }
  453. elseif (is_object($val)) {
  454. if (method_exists($val, 'printXML'))
  455. $val->printXML();
  456. elseif (method_exists($val, 'asXML')) {
  457. echo $val->asXML();
  458. }
  459. elseif (method_exists($val, 'asString'))
  460. echo XmlContent_quote($val->asString());
  461. else
  462. printf("==Object(%s)==", get_class($val));
  463. }
  464. elseif (is_array($val)) {
  465. // DEPRECATED:
  466. // Use XmlContent objects instead of arrays for collections of XmlElements.
  467. trigger_error("Passing arrays to PrintXML() is deprecated: (" . AsXML($val, true) . ")",
  468. E_USER_NOTICE);
  469. foreach ($val as $x)
  470. PrintXML($x);
  471. }
  472. else
  473. echo (string)XmlContent_quote((string)$val);
  474. }
  475. function AsXML ($val /* , ... */) {
  476. static $nowarn;
  477. if (func_num_args() > 1) {
  478. $xml = '';
  479. foreach (func_get_args() as $arg)
  480. $xml .= AsXML($arg);
  481. return $xml;
  482. }
  483. elseif (is_object($val)) {
  484. if (method_exists($val, 'asXML'))
  485. return $val->asXML();
  486. elseif (method_exists($val, 'asString'))
  487. return XmlContent_quote($val->asString());
  488. else
  489. return sprintf("==Object(%s)==", get_class($val));
  490. }
  491. elseif (is_array($val)) {
  492. // DEPRECATED:
  493. // Use XmlContent objects instead of arrays for collections of XmlElements.
  494. if (empty($nowarn)) {
  495. $nowarn = true;
  496. trigger_error("Passing arrays to AsXML() is deprecated: (" . AsXML($val) . ")",
  497. E_USER_NOTICE);
  498. unset($nowarn);
  499. }
  500. $xml = '';
  501. foreach ($val as $x)
  502. $xml .= AsXML($x);
  503. return $xml;
  504. }
  505. else
  506. return XmlContent_quote((string)$val);
  507. }
  508. function AsString ($val) {
  509. if (func_num_args() > 1) {
  510. $str = '';
  511. foreach (func_get_args() as $arg)
  512. $str .= AsString($arg);
  513. return $str;
  514. }
  515. elseif (is_object($val)) {
  516. if (method_exists($val, 'asString'))
  517. return $val->asString();
  518. else
  519. return sprintf("==Object(%s)==", get_class($val));
  520. }
  521. elseif (is_array($val)) {
  522. // DEPRECATED:
  523. // Use XmlContent objects instead of arrays for collections of XmlElements.
  524. trigger_error("Passing arrays to AsString() is deprecated", E_USER_NOTICE);
  525. $str = '';
  526. foreach ($val as $x)
  527. $str .= AsString($x);
  528. return $str;
  529. }
  530. return (string) $val;
  531. }
  532. function fmt ($fs /* , ... */) {
  533. $s = new FormattedText(false);
  534. $args = func_get_args();
  535. $args[0] = _($args[0]);
  536. $s->_init($args);
  537. return $s;
  538. }
  539. // $Log: XmlElement.php,v $
  540. // Revision 1.38 2005/10/10 19:36:09 rurban
  541. // fix comment
  542. //
  543. // Revision 1.37 2005/01/25 07:04:27 rurban
  544. // case-sensitive for php5
  545. //
  546. // Revision 1.36 2004/12/06 19:49:56 rurban
  547. // enable action=remove which is undoable and seeable in RecentChanges: ADODB ony for now.
  548. // renamed delete_page to purge_page.
  549. // enable action=edit&version=-1 to force creation of a new version.
  550. // added BABYCART_PATH config
  551. // fixed magiqc in adodb.inc.php
  552. // and some more docs
  553. //
  554. // Revision 1.35 2004/11/21 11:59:18 rurban
  555. // remove final \n to be ob_cache independent
  556. //
  557. // Revision 1.34 2004/10/12 13:13:19 rurban
  558. // php5 compatibility (5.0.1 ok)
  559. //
  560. // Revision 1.33 2004/07/02 09:55:58 rurban
  561. // more stability fixes: new DISABLE_GETIMAGESIZE if your php crashes when loading LinkIcons: failing getimagesize in old phps; blockparser stabilized
  562. //
  563. // Revision 1.32 2004/06/20 15:30:05 rurban
  564. // get_class case-sensitivity issues
  565. //
  566. // Revision 1.31 2004/06/20 14:42:54 rurban
  567. // various php5 fixes (still broken at blockparser)
  568. //
  569. // (c-file-style: "gnu")
  570. // Local Variables:
  571. // mode: php
  572. // tab-width: 8
  573. // c-basic-offset: 4
  574. // c-hanging-comment-ender-p: nil
  575. // indent-tabs-mode: nil
  576. // End:
  577. ?>