PageRenderTime 51ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/s3db3.5.10/pearlib/XML/Util.php

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