/class/xml/saxparser.php

https://gitlab.com/VoyaTrax/vtCMS · PHP · 373 lines · 204 code · 40 blank · 129 comment · 20 complexity · 92b35e8f4b9bae6070b1cd73adeb3159 MD5 · raw file

  1. <?php
  2. // $Id: saxparser.php 2 2005-11-02 18:23:29Z skalpa $
  3. /*******************************************************************************
  4. Location: <b>xml/SaxParser.class</b><br>
  5. <br>
  6. Provides basic functionality to read and parse XML documents. Subclasses
  7. must implement all the their custom handlers by using add* function methods.
  8. They may also use the handle*() methods to parse a specific XML begin and end
  9. tags, but this is not recommended as it is more difficult.<br>
  10. <br>
  11. Copyright &copy; 2001 eXtremePHP. All rights reserved.<br>
  12. <br>
  13. @author Ken Egervari<br>
  14. *******************************************************************************/
  15. class SaxParser
  16. {
  17. var $level;
  18. var $parser;
  19. var $isCaseFolding;
  20. var $targetEncoding;
  21. /* Custom Handler Variables */
  22. var $tagHandlers = array();
  23. /* Tag stack */
  24. var $tags = array();
  25. /* Xml Source Input */
  26. var $xmlInput;
  27. var $errors = array();
  28. /****************************************************************************
  29. Creates a SaxParser object using a FileInput to represent the stream
  30. of XML data to parse. Use the static methods createFileInput or
  31. createStringInput to construct xml input source objects to supply
  32. to the constructor, or the implementor can construct them individually.
  33. ****************************************************************************/
  34. function __construct($input)
  35. {
  36. $this->level = 0;
  37. $this->parser = xml_parser_create('UTF-8');
  38. xml_set_object($this->parser, $this);
  39. $this->input =& $input;
  40. $this->setCaseFolding(false);
  41. $this->useUtfEncoding();
  42. xml_set_element_handler($this->parser, 'handleBeginElement','handleEndElement');
  43. xml_set_character_data_handler($this->parser, 'handleCharacterData');
  44. xml_set_processing_instruction_handler($this->parser, 'handleProcessingInstruction');
  45. xml_set_default_handler($this->parser, 'handleDefault');
  46. xml_set_unparsed_entity_decl_handler($this->parser, 'handleUnparsedEntityDecl');
  47. xml_set_notation_decl_handler($this->parser, 'handleNotationDecl');
  48. xml_set_external_entity_ref_handler($this->parser, 'handleExternalEntityRef');
  49. }
  50. /*---------------------------------------------------------------------------
  51. Property Methods
  52. ---------------------------------------------------------------------------*/
  53. function getCurrentLevel()
  54. {
  55. return $this->level;
  56. }
  57. /****************************************************************************
  58. * @param $isCaseFolding
  59. * @returns void
  60. ****************************************************************************/
  61. function setCaseFolding($isCaseFolding)
  62. {
  63. assert(is_bool($isCaseFolding));
  64. $this->isCaseFolding = $isCaseFolding;
  65. xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, $this->isCaseFolding);
  66. }
  67. /****************************************************************************
  68. * @returns void
  69. ****************************************************************************/
  70. function useIsoEncoding()
  71. {
  72. $this->targetEncoding = 'ISO-8859-1';
  73. xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->targetEncoding);
  74. }
  75. /****************************************************************************
  76. * @returns void
  77. ****************************************************************************/
  78. function useAsciiEncoding()
  79. {
  80. $this->targetEncoding = 'US-ASCII';
  81. xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->targetEncoding);
  82. }
  83. /****************************************************************************
  84. * @returns void
  85. ****************************************************************************/
  86. function useUtfEncoding()
  87. {
  88. $this->targetEncoding = 'UTF-8';
  89. xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->targetEncoding);
  90. }
  91. /****************************************************************************
  92. Returns the name of the xml tag being parsed
  93. * @returns string
  94. ****************************************************************************/
  95. function getCurrentTag()
  96. {
  97. return $this->tags[count($this->tags) - 1];
  98. }
  99. function getParentTag()
  100. {
  101. if (isset($this->tags[count($this->tags) - 2])) {
  102. return $this->tags[count($this->tags) - 2];
  103. }
  104. return false;
  105. }
  106. /*---------------------------------------------------------------------------
  107. Parser methods
  108. ---------------------------------------------------------------------------*/
  109. /****************************************************************************
  110. * @returns void
  111. ****************************************************************************/
  112. function parse()
  113. {
  114. if (!is_bool($this->input)) {
  115. if (!xml_parse($this->parser, $this->input)) {
  116. $this->setErrors($this->getXmlError());
  117. return false;
  118. }
  119. //if (!$fp = fopen($this->input, 'r')) {
  120. // $this->setErrors('Could not open file: '.$this->input);
  121. // return false;
  122. //}
  123. } else {
  124. while ($data = fread($this->input, 4096)) {
  125. if (!xml_parse($this->parser, str_replace("'", "&apos;", $data), feof($this->input))) {
  126. $this->setErrors($this->getXmlError());
  127. fclose($this->input);
  128. return false;
  129. }
  130. }
  131. fclose($this->input);
  132. }
  133. return true;
  134. }
  135. /****************************************************************************
  136. * @returns void
  137. ****************************************************************************/
  138. function free()
  139. {
  140. xml_parser_free($this->parser);
  141. if (!method_exists($this, '__destruct')) {
  142. unset($this->parser);
  143. }
  144. else {
  145. $this->__destruct();
  146. }
  147. }
  148. /****************************************************************************
  149. * @private
  150. * @returns string
  151. ****************************************************************************/
  152. function getXmlError()
  153. {
  154. return sprintf("XmlParse error: %s at line %d", xml_error_string(xml_get_error_code($this->parser)), xml_get_current_line_number($this->parser));
  155. }
  156. /*---------------------------------------------------------------------------
  157. Custom Handler Methods
  158. ---------------------------------------------------------------------------*/
  159. /****************************************************************************
  160. Adds a callback function to be called when a tag is encountered.<br>
  161. Functions that are added must be of the form:<br>
  162. <b>functionName( $attributes )</b>
  163. * @param $tagName string. The name of the tag currently being parsed.
  164. * @param $functionName string. The name of the function in XmlDocument's
  165. subclass.
  166. * @returns void
  167. ****************************************************************************/
  168. function addTagHandler($tagHandler)
  169. {
  170. $name = $tagHandler->getName();
  171. if (is_array($name)) {
  172. foreach ($name as $n) {
  173. $this->tagHandlers[$n] = $tagHandler;
  174. }
  175. } else {
  176. $this->tagHandlers[$name] = $tagHandler;
  177. }
  178. }
  179. /*---------------------------------------------------------------------------
  180. Private Handler Methods
  181. ---------------------------------------------------------------------------*/
  182. /****************************************************************************
  183. Callback function that executes whenever a the start of a tag
  184. occurs when being parsed.
  185. * @param $parser int. The handle to the parser.
  186. * @param $tagName string. The name of the tag currently being parsed.
  187. * @param $attributesArray attay. The list of attributes associated with
  188. the tag.
  189. * @private
  190. * @returns void
  191. ****************************************************************************/
  192. function handleBeginElement($parser, $tagName, $attributesArray)
  193. {
  194. array_push($this->tags, $tagName);
  195. $this->level++;
  196. if (isset($this->tagHandlers[$tagName]) && is_subclass_of($this->tagHandlers[$tagName], 'xmltaghandler')) {
  197. $this->tagHandlers[$tagName]->handleBeginElement($this, $attributesArray);
  198. } else {
  199. $this->handleBeginElementDefault($parser, $tagName, $attributesArray);
  200. }
  201. }
  202. /****************************************************************************
  203. Callback function that executes whenever the end of a tag
  204. occurs when being parsed.
  205. * @param $parser int. The handle to the parser.
  206. * @param $tagName string. The name of the tag currently being parsed.
  207. * @private
  208. * @returns void
  209. ****************************************************************************/
  210. function handleEndElement($parser, $tagName)
  211. {
  212. array_pop($this->tags);
  213. if (isset($this->tagHandlers[$tagName]) && is_subclass_of($this->tagHandlers[$tagName], 'xmltaghandler')) {
  214. $this->tagHandlers[$tagName]->handleEndElement($this);
  215. } else {
  216. $this->handleEndElementDefault($parser, $tagName);
  217. }
  218. $this->level--;
  219. }
  220. /****************************************************************************
  221. Callback function that executes whenever character data is encountered
  222. while being parsed.
  223. * @param $parser int. The handle to the parser.
  224. * @param $data string. Character data inside the tag
  225. * @returns void
  226. ****************************************************************************/
  227. function handleCharacterData($parser, $data)
  228. {
  229. $tagHandler = $this->tagHandlers[$this->getCurrentTag()];
  230. if (isset($tagHandler) && is_subclass_of($tagHandler, 'xmltaghandler')) {
  231. $tagHandler->handleCharacterData($this, $data);
  232. } else {
  233. $this->handleCharacterDataDefault($parser, $data);
  234. }
  235. }
  236. /****************************************************************************
  237. * @param $parser int. The handle to the parser.
  238. * @returns void
  239. ****************************************************************************/
  240. function handleProcessingInstruction($parser, $target, $data)
  241. {
  242. // if($target == 'php') {
  243. // eval($data);
  244. // }
  245. }
  246. /****************************************************************************
  247. * @param $parser int. The handle to the parser.
  248. * @returns void
  249. ****************************************************************************/
  250. function handleDefault($parser, $data)
  251. {
  252. }
  253. /****************************************************************************
  254. * @param $parser int. The handle to the parser.
  255. * @returns void
  256. ****************************************************************************/
  257. function handleUnparsedEntityDecl($parser, $entityName, $base, $systemId, $publicId, $notationName)
  258. {
  259. }
  260. /****************************************************************************
  261. * @param $parser int. The handle to the parser.
  262. * @returns void
  263. ****************************************************************************/
  264. function handleNotationDecl($parser, $notationName, $base, $systemId, $publicId)
  265. {
  266. }
  267. /****************************************************************************
  268. * @param $parser int. The handle to the parser.
  269. * @returns void
  270. ****************************************************************************/
  271. function handleExternalEntityRef($parser, $openEntityNames, $base, $systemId, $publicId)
  272. {
  273. }
  274. /**
  275. * The default tag handler method for a tag with no handler
  276. *
  277. * @abstract
  278. */
  279. function handleBeginElementDefault($parser, $tagName, $attributesArray)
  280. {
  281. }
  282. /**
  283. * The default tag handler method for a tag with no handler
  284. *
  285. * @abstract
  286. */
  287. function handleEndElementDefault($parser, $tagName)
  288. {
  289. }
  290. /**
  291. * The default tag handler method for a tag with no handler
  292. *
  293. * @abstract
  294. */
  295. function handleCharacterDataDefault($parser, $data)
  296. {
  297. }
  298. /**
  299. * Sets error messages
  300. *
  301. * @param $error string an error message
  302. */
  303. function setErrors($error)
  304. {
  305. $this->errors[] = trim($error);
  306. }
  307. /**
  308. * Gets all the error messages
  309. *
  310. * @param $ashtml bool return as html?
  311. * @return mixed
  312. */
  313. function &getErrors($ashtml = true)
  314. {
  315. if (!$ashtml) {
  316. return $this->errors;
  317. } else {
  318. $ret = '';
  319. if (count($this->errors) > 0) {
  320. foreach ($this->errors as $error) {
  321. $ret .= $error.'<br />';
  322. }
  323. }
  324. return $ret;
  325. }
  326. }
  327. }
  328. ?>