PageRenderTime 51ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/php-webclient-ajax/server/PEAR/XML/Util.php

https://bitbucket.org/MelFlynn/zarafa
PHP | 794 lines | 300 code | 46 blank | 448 comment | 72 complexity | 34537bedaa113f7217af9c14740f25d1 MD5 | raw file
  1. <?php
  2. /*
  3. * Copyright 2005 - 2009 Zarafa B.V.
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License, version 3,
  7. * as published by the Free Software Foundation with the following additional
  8. * term according to sec. 7:
  9. *
  10. * According to sec. 7 of the GNU Affero General Public License, version
  11. * 3, the terms of the AGPL are supplemented with the following terms:
  12. *
  13. * "Zarafa" is a registered trademark of Zarafa B.V. The licensing of
  14. * the Program under the AGPL does not imply a trademark license.
  15. * Therefore any rights, title and interest in our trademarks remain
  16. * entirely with us.
  17. *
  18. * However, if you propagate an unmodified version of the Program you are
  19. * allowed to use the term "Zarafa" to indicate that you distribute the
  20. * Program. Furthermore you may use our trademarks where it is necessary
  21. * to indicate the intended purpose of a product or service provided you
  22. * use it in accordance with honest practices in industrial or commercial
  23. * matters. If you want to propagate modified versions of the Program
  24. * under the name "Zarafa" or "Zarafa Server", you may only do so if you
  25. * have a written permission by Zarafa B.V. (to acquire a permission
  26. * please contact Zarafa at trademark@zarafa.com).
  27. *
  28. * The interactive user interface of the software displays an attribution
  29. * notice containing the term "Zarafa" and/or the logo of Zarafa.
  30. * Interactive user interfaces of unmodified and modified versions must
  31. * display Appropriate Legal Notices according to sec. 5 of the GNU
  32. * Affero General Public License, version 3, when you propagate
  33. * unmodified or modified versions of the Program. In accordance with
  34. * sec. 7 b) of the GNU Affero General Public License, version 3, these
  35. * Appropriate Legal Notices must retain the logo of Zarafa or display
  36. * the words "Initial Development by Zarafa" if the display of the logo
  37. * is not reasonably feasible for technical reasons. The use of the logo
  38. * of Zarafa in Legal Notices is allowed for unmodified and modified
  39. * versions of the software.
  40. *
  41. * This program is distributed in the hope that it will be useful,
  42. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  43. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  44. * GNU Affero General Public License for more details.
  45. *
  46. * You should have received a copy of the GNU Affero General Public License
  47. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  48. *
  49. */
  50. ?>
  51. <?PHP
  52. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  53. // +----------------------------------------------------------------------+
  54. // | PHP Version 4 |
  55. // +----------------------------------------------------------------------+
  56. // | Copyright (c) 1997-2002 The PHP Group |
  57. // +----------------------------------------------------------------------+
  58. // | This source file is subject to version 2.0 of the PHP license, |
  59. // | that is bundled with this package in the file LICENSE, and is |
  60. // | available at through the world-wide-web at |
  61. // | http://www.php.net/license/2_02.txt. |
  62. // | If you did not receive a copy of the PHP license and are unable to |
  63. // | obtain it through the world-wide-web, please send a note to |
  64. // | license@php.net so we can mail you a copy immediately. |
  65. // +----------------------------------------------------------------------+
  66. // | Authors: Stephan Schmidt <schst@php-tools.net> |
  67. // +----------------------------------------------------------------------+
  68. //
  69. // $Id: Util.php,v 1.24 2004/12/23 13:21:59 schst Exp $
  70. /**
  71. * error code for invalid chars in XML name
  72. */
  73. define("XML_UTIL_ERROR_INVALID_CHARS", 51);
  74. /**
  75. * error code for invalid chars in XML name
  76. */
  77. define("XML_UTIL_ERROR_INVALID_START", 52);
  78. /**
  79. * error code for non-scalar tag content
  80. */
  81. define("XML_UTIL_ERROR_NON_SCALAR_CONTENT", 60);
  82. /**
  83. * error code for missing tag name
  84. */
  85. define("XML_UTIL_ERROR_NO_TAG_NAME", 61);
  86. /**
  87. * replace XML entities
  88. */
  89. define("XML_UTIL_REPLACE_ENTITIES", 1);
  90. /**
  91. * embedd content in a CData Section
  92. */
  93. define("XML_UTIL_CDATA_SECTION", 5);
  94. /**
  95. * do not replace entitites
  96. */
  97. define("XML_UTIL_ENTITIES_NONE", 0);
  98. /**
  99. * replace all XML entitites
  100. * This setting will replace <, >, ", ' and &
  101. */
  102. define("XML_UTIL_ENTITIES_XML", 1);
  103. /**
  104. * replace only required XML entitites
  105. * This setting will replace <, " and &
  106. */
  107. define("XML_UTIL_ENTITIES_XML_REQUIRED", 2);
  108. /**
  109. * replace HTML entitites
  110. * @link http://www.php.net/htmlentities
  111. */
  112. define("XML_UTIL_ENTITIES_HTML", 3);
  113. /**
  114. * Collapse all empty tags.
  115. */
  116. define("XML_UTIL_COLLAPSE_ALL", 1);
  117. /**
  118. * Collapse only empty XHTML tags that have no end tag.
  119. */
  120. define("XML_UTIL_COLLAPSE_XHTML_ONLY", 2);
  121. /**
  122. * utility class for working with XML documents
  123. *
  124. * @category XML
  125. * @package XML_Util
  126. * @version 1.1.0
  127. * @author Stephan Schmidt <schst@php.net>
  128. */
  129. class XML_Util {
  130. /**
  131. * return API version
  132. *
  133. * @access public
  134. * @static
  135. * @return string $version API version
  136. */
  137. function apiVersion()
  138. {
  139. return '1.1';
  140. }
  141. /**
  142. * replace XML entities
  143. *
  144. * With the optional second parameter, you may select, which
  145. * entities should be replaced.
  146. *
  147. * <code>
  148. * require_once 'XML/Util.php';
  149. *
  150. * // replace XML entites:
  151. * $string = XML_Util::replaceEntities("This string contains < & >.");
  152. * </code>
  153. *
  154. * @access public
  155. * @static
  156. * @param string string where XML special chars should be replaced
  157. * @param integer setting for entities in attribute values (one of XML_UTIL_ENTITIES_XML, XML_UTIL_ENTITIES_XML_REQUIRED, XML_UTIL_ENTITIES_HTML)
  158. * @return string string with replaced chars
  159. * @see reverseEntities()
  160. */
  161. function replaceEntities($string, $replaceEntities = XML_UTIL_ENTITIES_XML)
  162. {
  163. switch ($replaceEntities) {
  164. case XML_UTIL_ENTITIES_XML:
  165. return strtr($string,array(
  166. '&' => '&amp;',
  167. '>' => '&gt;',
  168. '<' => '&lt;',
  169. '"' => '&quot;',
  170. '\'' => '&apos;' ));
  171. break;
  172. case XML_UTIL_ENTITIES_XML_REQUIRED:
  173. return strtr($string,array(
  174. '&' => '&amp;',
  175. '<' => '&lt;',
  176. '"' => '&quot;' ));
  177. break;
  178. case XML_UTIL_ENTITIES_HTML:
  179. return htmlentities($string);
  180. break;
  181. }
  182. return $string;
  183. }
  184. /**
  185. * reverse XML entities
  186. *
  187. * With the optional second parameter, you may select, which
  188. * entities should be reversed.
  189. *
  190. * <code>
  191. * require_once 'XML/Util.php';
  192. *
  193. * // reverse XML entites:
  194. * $string = XML_Util::reverseEntities("This string contains &lt; &amp; &gt;.");
  195. * </code>
  196. *
  197. * @access public
  198. * @static
  199. * @param string string where XML special chars should be replaced
  200. * @param integer setting for entities in attribute values (one of XML_UTIL_ENTITIES_XML, XML_UTIL_ENTITIES_XML_REQUIRED, XML_UTIL_ENTITIES_HTML)
  201. * @return string string with replaced chars
  202. * @see replaceEntities()
  203. */
  204. function reverseEntities($string, $replaceEntities = XML_UTIL_ENTITIES_XML)
  205. {
  206. switch ($replaceEntities) {
  207. case XML_UTIL_ENTITIES_XML:
  208. return strtr($string,array(
  209. '&amp;' => '&',
  210. '&gt;' => '>',
  211. '&lt;' => '<',
  212. '&quot;' => '"',
  213. '&apos;' => '\'' ));
  214. break;
  215. case XML_UTIL_ENTITIES_XML_REQUIRED:
  216. return strtr($string,array(
  217. '&amp;' => '&',
  218. '&lt;' => '<',
  219. '&quot;' => '"' ));
  220. break;
  221. case XML_UTIL_ENTITIES_HTML:
  222. $arr = array_flip(get_html_translation_table(HTML_ENTITIES));
  223. return strtr($string, $arr);
  224. break;
  225. }
  226. return $string;
  227. }
  228. /**
  229. * build an xml declaration
  230. *
  231. * <code>
  232. * require_once 'XML/Util.php';
  233. *
  234. * // get an XML declaration:
  235. * $xmlDecl = XML_Util::getXMLDeclaration("1.0", "UTF-8", true);
  236. * </code>
  237. *
  238. * @access public
  239. * @static
  240. * @param string $version xml version
  241. * @param string $encoding character encoding
  242. * @param boolean $standAlone document is standalone (or not)
  243. * @return string $decl xml declaration
  244. * @uses XML_Util::attributesToString() to serialize the attributes of the XML declaration
  245. */
  246. function getXMLDeclaration($version = "1.0", $encoding = null, $standalone = null)
  247. {
  248. $attributes = array(
  249. "version" => $version,
  250. );
  251. // add encoding
  252. if ($encoding !== null) {
  253. $attributes["encoding"] = $encoding;
  254. }
  255. // add standalone, if specified
  256. if ($standalone !== null) {
  257. $attributes["standalone"] = $standalone ? "yes" : "no";
  258. }
  259. return sprintf("<?xml%s?>", XML_Util::attributesToString($attributes, false));
  260. }
  261. /**
  262. * build a document type declaration
  263. *
  264. * <code>
  265. * require_once 'XML/Util.php';
  266. *
  267. * // get a doctype declaration:
  268. * $xmlDecl = XML_Util::getDocTypeDeclaration("rootTag","myDocType.dtd");
  269. * </code>
  270. *
  271. * @access public
  272. * @static
  273. * @param string $root name of the root tag
  274. * @param string $uri uri of the doctype definition (or array with uri and public id)
  275. * @param string $internalDtd internal dtd entries
  276. * @return string $decl doctype declaration
  277. * @since 0.2
  278. */
  279. function getDocTypeDeclaration($root, $uri = null, $internalDtd = null)
  280. {
  281. if (is_array($uri)) {
  282. $ref = sprintf( ' PUBLIC "%s" "%s"', $uri["id"], $uri["uri"] );
  283. } elseif (!empty($uri)) {
  284. $ref = sprintf( ' SYSTEM "%s"', $uri );
  285. } else {
  286. $ref = "";
  287. }
  288. if (empty($internalDtd)) {
  289. return sprintf("<!DOCTYPE %s%s>", $root, $ref);
  290. } else {
  291. return sprintf("<!DOCTYPE %s%s [\n%s\n]>", $root, $ref, $internalDtd);
  292. }
  293. }
  294. /**
  295. * create string representation of an attribute list
  296. *
  297. * <code>
  298. * require_once 'XML/Util.php';
  299. *
  300. * // build an attribute string
  301. * $att = array(
  302. * "foo" => "bar",
  303. * "argh" => "tomato"
  304. * );
  305. *
  306. * $attList = XML_Util::attributesToString($att);
  307. * </code>
  308. *
  309. * @access public
  310. * @static
  311. * @param array $attributes attribute array
  312. * @param boolean|array $sort sort attribute list alphabetically, may also be an assoc array containing the keys 'sort', 'multiline', 'indent', 'linebreak' and 'entities'
  313. * @param boolean $multiline use linebreaks, if more than one attribute is given
  314. * @param string $indent string used for indentation of multiline attributes
  315. * @param string $linebreak string used for linebreaks of multiline attributes
  316. * @param integer $entities setting for entities in attribute values (one of XML_UTIL_ENTITIES_NONE, XML_UTIL_ENTITIES_XML, XML_UTIL_ENTITIES_XML_REQUIRED, XML_UTIL_ENTITIES_HTML)
  317. * @return string string representation of the attributes
  318. * @uses XML_Util::replaceEntities() to replace XML entities in attribute values
  319. * @todo allow sort also to be an options array
  320. */
  321. function attributesToString($attributes, $sort = true, $multiline = false, $indent = ' ', $linebreak = "\n", $entities = XML_UTIL_ENTITIES_XML)
  322. {
  323. /**
  324. * second parameter may be an array
  325. */
  326. if (is_array($sort)) {
  327. if (isset($sort['multiline'])) {
  328. $multiline = $sort['multiline'];
  329. }
  330. if (isset($sort['indent'])) {
  331. $indent = $sort['indent'];
  332. }
  333. if (isset($sort['linebreak'])) {
  334. $multiline = $sort['linebreak'];
  335. }
  336. if (isset($sort['entities'])) {
  337. $entities = $sort['entities'];
  338. }
  339. if (isset($sort['sort'])) {
  340. $sort = $sort['sort'];
  341. } else {
  342. $sort = true;
  343. }
  344. }
  345. $string = '';
  346. if (is_array($attributes) && !empty($attributes)) {
  347. if ($sort) {
  348. ksort($attributes);
  349. }
  350. if( !$multiline || count($attributes) == 1) {
  351. foreach ($attributes as $key => $value) {
  352. if ($entities != XML_UTIL_ENTITIES_NONE) {
  353. if ($entities === XML_UTIL_CDATA_SECTION) {
  354. $entities = XML_UTIL_ENTITIES_XML;
  355. }
  356. $value = XML_Util::replaceEntities($value, $entities);
  357. }
  358. $string .= ' '.$key.'="'.$value.'"';
  359. }
  360. } else {
  361. $first = true;
  362. foreach ($attributes as $key => $value) {
  363. if ($entities != XML_UTIL_ENTITIES_NONE) {
  364. $value = XML_Util::replaceEntities($value, $entities);
  365. }
  366. if ($first) {
  367. $string .= " ".$key.'="'.$value.'"';
  368. $first = false;
  369. } else {
  370. $string .= $linebreak.$indent.$key.'="'.$value.'"';
  371. }
  372. }
  373. }
  374. }
  375. return $string;
  376. }
  377. /**
  378. * Collapses empty tags.
  379. *
  380. * @access public
  381. * @static
  382. * @param string $xml XML
  383. * @param integer $mode Whether to collapse all empty tags (XML_UTIL_COLLAPSE_ALL) or only XHTML (XML_UTIL_COLLAPSE_XHTML_ONLY) ones.
  384. * @return string $xml XML
  385. */
  386. function collapseEmptyTags($xml, $mode = XML_UTIL_COLLAPSE_ALL) {
  387. if ($mode == XML_UTIL_COLLAPSE_XHTML_ONLY) {
  388. return preg_replace(
  389. '/<(area|base|br|col|hr|img|input|link|meta|param)([^>]*)><\/\\1>/s',
  390. '<\\1\\2 />',
  391. $xml
  392. );
  393. } else {
  394. return preg_replace(
  395. '/<(\w+)([^>]*)><\/\\1>/s',
  396. '<\\1\\2 />',
  397. $xml
  398. );
  399. }
  400. }
  401. /**
  402. * create a tag
  403. *
  404. * This method will call XML_Util::createTagFromArray(), which
  405. * is more flexible.
  406. *
  407. * <code>
  408. * require_once 'XML/Util.php';
  409. *
  410. * // create an XML tag:
  411. * $tag = XML_Util::createTag("myNs:myTag", array("foo" => "bar"), "This is inside the tag", "http://www.w3c.org/myNs#");
  412. * </code>
  413. *
  414. * @access public
  415. * @static
  416. * @param string $qname qualified tagname (including namespace)
  417. * @param array $attributes array containg attributes
  418. * @param mixed $content
  419. * @param string $namespaceUri URI of the namespace
  420. * @param integer $replaceEntities whether to replace XML special chars in content, embedd it in a CData section or none of both
  421. * @param boolean $multiline whether to create a multiline tag where each attribute gets written to a single line
  422. * @param string $indent string used to indent attributes (_auto indents attributes so they start at the same column)
  423. * @param string $linebreak string used for linebreaks
  424. * @return string $string XML tag
  425. * @see XML_Util::createTagFromArray()
  426. * @uses XML_Util::createTagFromArray() to create the tag
  427. */
  428. function createTag($qname, $attributes = array(), $content = null, $namespaceUri = null, $replaceEntities = XML_UTIL_REPLACE_ENTITIES, $multiline = false, $indent = "_auto", $linebreak = "\n")
  429. {
  430. $tag = array(
  431. "qname" => $qname,
  432. "attributes" => $attributes
  433. );
  434. // add tag content
  435. if ($content !== null) {
  436. $tag["content"] = $content;
  437. }
  438. // add namespace Uri
  439. if ($namespaceUri !== null) {
  440. $tag["namespaceUri"] = $namespaceUri;
  441. }
  442. return XML_Util::createTagFromArray($tag, $replaceEntities, $multiline, $indent, $linebreak);
  443. }
  444. /**
  445. * create a tag from an array
  446. * this method awaits an array in the following format
  447. * <pre>
  448. * array(
  449. * "qname" => $qname // qualified name of the tag
  450. * "namespace" => $namespace // namespace prefix (optional, if qname is specified or no namespace)
  451. * "localpart" => $localpart, // local part of the tagname (optional, if qname is specified)
  452. * "attributes" => array(), // array containing all attributes (optional)
  453. * "content" => $content, // tag content (optional)
  454. * "namespaceUri" => $namespaceUri // namespaceUri for the given namespace (optional)
  455. * )
  456. * </pre>
  457. *
  458. * <code>
  459. * require_once 'XML/Util.php';
  460. *
  461. * $tag = array(
  462. * "qname" => "foo:bar",
  463. * "namespaceUri" => "http://foo.com",
  464. * "attributes" => array( "key" => "value", "argh" => "fruit&vegetable" ),
  465. * "content" => "I'm inside the tag",
  466. * );
  467. * // creating a tag with qualified name and namespaceUri
  468. * $string = XML_Util::createTagFromArray($tag);
  469. * </code>
  470. *
  471. * @access public
  472. * @static
  473. * @param array $tag tag definition
  474. * @param integer $replaceEntities whether to replace XML special chars in content, embedd it in a CData section or none of both
  475. * @param boolean $multiline whether to create a multiline tag where each attribute gets written to a single line
  476. * @param string $indent string used to indent attributes (_auto indents attributes so they start at the same column)
  477. * @param string $linebreak string used for linebreaks
  478. * @return string $string XML tag
  479. * @see XML_Util::createTag()
  480. * @uses XML_Util::attributesToString() to serialize the attributes of the tag
  481. * @uses XML_Util::splitQualifiedName() to get local part and namespace of a qualified name
  482. */
  483. function createTagFromArray($tag, $replaceEntities = XML_UTIL_REPLACE_ENTITIES, $multiline = false, $indent = "_auto", $linebreak = "\n" )
  484. {
  485. if (isset($tag['content']) && !is_scalar($tag['content'])) {
  486. return XML_Util::raiseError( 'Supplied non-scalar value as tag content', XML_UTIL_ERROR_NON_SCALAR_CONTENT );
  487. }
  488. if (!isset($tag['qname']) && !isset($tag['localPart'])) {
  489. return XML_Util::raiseError( 'You must either supply a qualified name (qname) or local tag name (localPart).', XML_UTIL_ERROR_NO_TAG_NAME );
  490. }
  491. // if no attributes hav been set, use empty attributes
  492. if (!isset($tag["attributes"]) || !is_array($tag["attributes"])) {
  493. $tag["attributes"] = array();
  494. }
  495. // qualified name is not given
  496. if (!isset($tag["qname"])) {
  497. // check for namespace
  498. if (isset($tag["namespace"]) && !empty($tag["namespace"])) {
  499. $tag["qname"] = $tag["namespace"].":".$tag["localPart"];
  500. } else {
  501. $tag["qname"] = $tag["localPart"];
  502. }
  503. // namespace URI is set, but no namespace
  504. } elseif (isset($tag["namespaceUri"]) && !isset($tag["namespace"])) {
  505. $parts = XML_Util::splitQualifiedName($tag["qname"]);
  506. $tag["localPart"] = $parts["localPart"];
  507. if (isset($parts["namespace"])) {
  508. $tag["namespace"] = $parts["namespace"];
  509. }
  510. }
  511. if (isset($tag["namespaceUri"]) && !empty($tag["namespaceUri"])) {
  512. // is a namespace given
  513. if (isset($tag["namespace"]) && !empty($tag["namespace"])) {
  514. $tag["attributes"]["xmlns:".$tag["namespace"]] = $tag["namespaceUri"];
  515. } else {
  516. // define this Uri as the default namespace
  517. $tag["attributes"]["xmlns"] = $tag["namespaceUri"];
  518. }
  519. }
  520. // check for multiline attributes
  521. if ($multiline === true) {
  522. if ($indent === "_auto") {
  523. $indent = str_repeat(" ", (strlen($tag["qname"])+2));
  524. }
  525. }
  526. // create attribute list
  527. $attList = XML_Util::attributesToString($tag['attributes'], true, $multiline, $indent, $linebreak, $replaceEntities );
  528. if (!isset($tag['content']) || (string)$tag['content'] == '') {
  529. $tag = sprintf('<%s%s />', $tag['qname'], $attList);
  530. } else {
  531. switch ($replaceEntities) {
  532. case XML_UTIL_ENTITIES_NONE:
  533. break;
  534. case XML_UTIL_CDATA_SECTION:
  535. $tag['content'] = XML_Util::createCDataSection($tag['content']);
  536. break;
  537. default:
  538. $tag['content'] = XML_Util::replaceEntities($tag['content'], $replaceEntities);
  539. break;
  540. }
  541. $tag = sprintf('<%s%s>%s</%s>', $tag['qname'], $attList, $tag['content'], $tag['qname'] );
  542. }
  543. return $tag;
  544. }
  545. /**
  546. * create a start element
  547. *
  548. * <code>
  549. * require_once 'XML/Util.php';
  550. *
  551. * // create an XML start element:
  552. * $tag = XML_Util::createStartElement("myNs:myTag", array("foo" => "bar") ,"http://www.w3c.org/myNs#");
  553. * </code>
  554. *
  555. * @access public
  556. * @static
  557. * @param string $qname qualified tagname (including namespace)
  558. * @param array $attributes array containg attributes
  559. * @param string $namespaceUri URI of the namespace
  560. * @param boolean $multiline whether to create a multiline tag where each attribute gets written to a single line
  561. * @param string $indent string used to indent attributes (_auto indents attributes so they start at the same column)
  562. * @param string $linebreak string used for linebreaks
  563. * @return string $string XML start element
  564. * @see XML_Util::createEndElement(), XML_Util::createTag()
  565. */
  566. function createStartElement($qname, $attributes = array(), $namespaceUri = null, $multiline = false, $indent = '_auto', $linebreak = "\n")
  567. {
  568. // if no attributes hav been set, use empty attributes
  569. if (!isset($attributes) || !is_array($attributes)) {
  570. $attributes = array();
  571. }
  572. if ($namespaceUri != null) {
  573. $parts = XML_Util::splitQualifiedName($qname);
  574. }
  575. // check for multiline attributes
  576. if ($multiline === true) {
  577. if ($indent === "_auto") {
  578. $indent = str_repeat(" ", (strlen($qname)+2));
  579. }
  580. }
  581. if ($namespaceUri != null) {
  582. // is a namespace given
  583. if (isset($parts["namespace"]) && !empty($parts["namespace"])) {
  584. $attributes["xmlns:".$parts["namespace"]] = $namespaceUri;
  585. } else {
  586. // define this Uri as the default namespace
  587. $attributes["xmlns"] = $namespaceUri;
  588. }
  589. }
  590. // create attribute list
  591. $attList = XML_Util::attributesToString($attributes, true, $multiline, $indent, $linebreak);
  592. $element = sprintf("<%s%s>", $qname, $attList);
  593. return $element;
  594. }
  595. /**
  596. * create an end element
  597. *
  598. * <code>
  599. * require_once 'XML/Util.php';
  600. *
  601. * // create an XML start element:
  602. * $tag = XML_Util::createEndElement("myNs:myTag");
  603. * </code>
  604. *
  605. * @access public
  606. * @static
  607. * @param string $qname qualified tagname (including namespace)
  608. * @return string $string XML end element
  609. * @see XML_Util::createStartElement(), XML_Util::createTag()
  610. */
  611. function createEndElement($qname)
  612. {
  613. $element = sprintf("</%s>", $qname);
  614. return $element;
  615. }
  616. /**
  617. * create an XML comment
  618. *
  619. * <code>
  620. * require_once 'XML/Util.php';
  621. *
  622. * // create an XML start element:
  623. * $tag = XML_Util::createComment("I am a comment");
  624. * </code>
  625. *
  626. * @access public
  627. * @static
  628. * @param string $content content of the comment
  629. * @return string $comment XML comment
  630. */
  631. function createComment($content)
  632. {
  633. $comment = sprintf("<!-- %s -->", $content);
  634. return $comment;
  635. }
  636. /**
  637. * create a CData section
  638. *
  639. * <code>
  640. * require_once 'XML/Util.php';
  641. *
  642. * // create a CData section
  643. * $tag = XML_Util::createCDataSection("I am content.");
  644. * </code>
  645. *
  646. * @access public
  647. * @static
  648. * @param string $data data of the CData section
  649. * @return string $string CData section with content
  650. */
  651. function createCDataSection($data)
  652. {
  653. return sprintf("<![CDATA[%s]]>", $data);
  654. }
  655. /**
  656. * split qualified name and return namespace and local part
  657. *
  658. * <code>
  659. * require_once 'XML/Util.php';
  660. *
  661. * // split qualified tag
  662. * $parts = XML_Util::splitQualifiedName("xslt:stylesheet");
  663. * </code>
  664. * the returned array will contain two elements:
  665. * <pre>
  666. * array(
  667. * "namespace" => "xslt",
  668. * "localPart" => "stylesheet"
  669. * );
  670. * </pre>
  671. *
  672. * @access public
  673. * @static
  674. * @param string $qname qualified tag name
  675. * @param string $defaultNs default namespace (optional)
  676. * @return array $parts array containing namespace and local part
  677. */
  678. function splitQualifiedName($qname, $defaultNs = null)
  679. {
  680. if (strstr($qname, ':')) {
  681. $tmp = explode(":", $qname);
  682. return array(
  683. "namespace" => $tmp[0],
  684. "localPart" => $tmp[1]
  685. );
  686. }
  687. return array(
  688. "namespace" => $defaultNs,
  689. "localPart" => $qname
  690. );
  691. }
  692. /**
  693. * check, whether string is valid XML name
  694. *
  695. * <p>XML names are used for tagname, attribute names and various
  696. * other, lesser known entities.</p>
  697. * <p>An XML name may only consist of alphanumeric characters,
  698. * dashes, undescores and periods, and has to start with a letter
  699. * or an underscore.
  700. * </p>
  701. *
  702. * <code>
  703. * require_once 'XML/Util.php';
  704. *
  705. * // verify tag name
  706. * $result = XML_Util::isValidName("invalidTag?");
  707. * if (XML_Util::isError($result)) {
  708. * print "Invalid XML name: " . $result->getMessage();
  709. * }
  710. * </code>
  711. *
  712. * @access public
  713. * @static
  714. * @param string $string string that should be checked
  715. * @return mixed $valid true, if string is a valid XML name, PEAR error otherwise
  716. * @todo support for other charsets
  717. */
  718. function isValidName($string)
  719. {
  720. // check for invalid chars
  721. if (!preg_match("/^[[:alnum:]_\-.]$/", $string{0})) {
  722. return XML_Util::raiseError( "XML names may only start with letter or underscore", XML_UTIL_ERROR_INVALID_START );
  723. }
  724. // check for invalid chars
  725. if (!preg_match("/^([a-zA-Z_]([a-zA-Z0-9_\-\.]*)?:)?[a-zA-Z_]([a-zA-Z0-9_\-\.]+)?$/", $string)) {
  726. return XML_Util::raiseError( "XML names may only contain alphanumeric chars, period, hyphen, colon and underscores", XML_UTIL_ERROR_INVALID_CHARS );
  727. }
  728. // XML name is valid
  729. return true;
  730. }
  731. /**
  732. * replacement for XML_Util::raiseError
  733. *
  734. * Avoids the necessity to always require
  735. * PEAR.php
  736. *
  737. * @access public
  738. * @param string error message
  739. * @param integer error code
  740. * @return object PEAR_Error
  741. */
  742. function raiseError($msg, $code)
  743. {
  744. require_once 'PEAR.php';
  745. return PEAR::raiseError($msg, $code);
  746. }
  747. }
  748. ?>