/class/xml/saxparser.php

https://gitlab.com/VoyaTrax/vtCMS3 · PHP · 392 lines · 319 code · 19 blank · 54 comment · 6 complexity · 1b8bbeea3c1d685a020ac2a1684bf145 MD5 · raw file

  1. <?php
  2. // $Id: saxparser.php 10761 2013-01-11 18:39:56Z trabis $
  3. /*******************************************************************************
  4. Location: <strong>xml/SaxParser.class</strong><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. * @param $input
  35. */
  36. function __construct(&$input)
  37. {
  38. $this->level = 0;
  39. $this->parser = xml_parser_create('UTF-8');
  40. xml_set_object($this->parser, $this);
  41. $this->input = $input;
  42. $this->setCaseFolding(false);
  43. $this->useUtfEncoding();
  44. xml_set_element_handler($this->parser, 'handleBeginElement', 'handleEndElement');
  45. xml_set_character_data_handler($this->parser, 'handleCharacterData');
  46. xml_set_processing_instruction_handler($this->parser, 'handleProcessingInstruction');
  47. xml_set_default_handler($this->parser, 'handleDefault');
  48. xml_set_unparsed_entity_decl_handler($this->parser, 'handleUnparsedEntityDecl');
  49. xml_set_notation_decl_handler($this->parser, 'handleNotationDecl');
  50. xml_set_external_entity_ref_handler($this->parser, 'handleExternalEntityRef');
  51. }
  52. /*---------------------------------------------------------------------------
  53. Property Methods
  54. ---------------------------------------------------------------------------*/
  55. function getCurrentLevel()
  56. {
  57. return $this->level;
  58. }
  59. /****************************************************************************
  60. * @param $isCaseFolding
  61. * @returns void
  62. ****************************************************************************/
  63. function setCaseFolding($isCaseFolding)
  64. {
  65. assert(is_bool($isCaseFolding));
  66. $this->isCaseFolding = $isCaseFolding;
  67. xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, $this->isCaseFolding);
  68. }
  69. /****************************************************************************
  70. * @returns void
  71. ****************************************************************************/
  72. function useIsoEncoding()
  73. {
  74. $this->targetEncoding = 'ISO-8859-1';
  75. xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->targetEncoding);
  76. }
  77. /****************************************************************************
  78. * @returns void
  79. ****************************************************************************/
  80. function useAsciiEncoding()
  81. {
  82. $this->targetEncoding = 'US-ASCII';
  83. xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->targetEncoding);
  84. }
  85. /****************************************************************************
  86. * @returns void
  87. ****************************************************************************/
  88. function useUtfEncoding()
  89. {
  90. $this->targetEncoding = 'UTF-8';
  91. xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->targetEncoding);
  92. }
  93. /****************************************************************************
  94. Returns the name of the xml tag being parsed
  95. * @returns string
  96. ****************************************************************************/
  97. function getCurrentTag()
  98. {
  99. return $this->tags[count($this->tags) - 1];
  100. }
  101. function getParentTag()
  102. {
  103. if (isset($this->tags[count($this->tags) - 2])) {
  104. return $this->tags[count($this->tags) - 2];
  105. }
  106. return false;
  107. }
  108. /*---------------------------------------------------------------------------
  109. Parser methods
  110. ---------------------------------------------------------------------------*/
  111. /**
  112. * @return bool
  113. */
  114. function parse()
  115. {
  116. if (!is_resource($this->input)) {
  117. if (!xml_parse($this->parser, $this->input)) {
  118. $this->setErrors($this->getXmlError());
  119. return false;
  120. }
  121. //if (!$fp = fopen($this->input, 'r')) {
  122. // $this->setErrors('Could not open file: '.$this->input);
  123. // return false;
  124. //}
  125. } else {
  126. while ($data = fread($this->input, 4096)) {
  127. if (!xml_parse($this->parser, str_replace("'", "&apos;", $data), feof($this->input))) {
  128. $this->setErrors($this->getXmlError());
  129. fclose($this->input);
  130. return false;
  131. }
  132. }
  133. fclose($this->input);
  134. }
  135. return true;
  136. }
  137. /****************************************************************************
  138. * @returns void
  139. ****************************************************************************/
  140. function free()
  141. {
  142. xml_parser_free($this->parser);
  143. if (!method_exists($this, '__destruct')) {
  144. unset($this);
  145. } else {
  146. $this->__destruct();
  147. }
  148. }
  149. /**
  150. * @private
  151. * @return string
  152. */
  153. function getXmlError()
  154. {
  155. return sprintf("XmlParse error: %s at line %d", xml_error_string(xml_get_error_code($this->parser)), xml_get_current_line_number($this->parser));
  156. }
  157. /*---------------------------------------------------------------------------
  158. Custom Handler Methods
  159. ---------------------------------------------------------------------------*/
  160. /**
  161. * Adds a callback function to be called when a tag is encountered.<br>
  162. * @param XmlTagHandler $tagHandler
  163. * @return void
  164. */
  165. function addTagHandler(XmlTagHandler &$tagHandler)
  166. {
  167. $name = $tagHandler->getName();
  168. if (is_array($name)) {
  169. foreach ($name as $n) {
  170. $this->tagHandlers[$n] = $tagHandler;
  171. }
  172. } else {
  173. $this->tagHandlers[$name] = $tagHandler;
  174. }
  175. }
  176. /*---------------------------------------------------------------------------
  177. Private Handler Methods
  178. ---------------------------------------------------------------------------*/
  179. /****************************************************************************
  180. Callback function that executes whenever a the start of a tag
  181. occurs when being parsed.
  182. * @param $parser int. The handle to the parser.
  183. * @param $tagName string. The name of the tag currently being parsed.
  184. * @param $attributesArray attay. The list of attributes associated with
  185. the tag.
  186. * @private
  187. * @returns void
  188. ****************************************************************************/
  189. function handleBeginElement($parser, $tagName, $attributesArray)
  190. {
  191. array_push($this->tags, $tagName);
  192. $this->level++;
  193. if (isset($this->tagHandlers[$tagName]) && is_subclass_of($this->tagHandlers[$tagName], 'xmltaghandler')) {
  194. $this->tagHandlers[$tagName]->handleBeginElement($this, $attributesArray);
  195. } else {
  196. $this->handleBeginElementDefault($parser, $tagName, $attributesArray);
  197. }
  198. }
  199. /****************************************************************************
  200. Callback function that executes whenever the end of a tag
  201. occurs when being parsed.
  202. * @param $parser int. The handle to the parser.
  203. * @param $tagName string. The name of the tag currently being parsed.
  204. * @private
  205. * @returns void
  206. ****************************************************************************/
  207. function handleEndElement($parser, $tagName)
  208. {
  209. array_pop($this->tags);
  210. if (isset($this->tagHandlers[$tagName]) && is_subclass_of($this->tagHandlers[$tagName], 'xmltaghandler')) {
  211. $this->tagHandlers[$tagName]->handleEndElement($this);
  212. } else {
  213. $this->handleEndElementDefault($parser, $tagName);
  214. }
  215. $this->level--;
  216. }
  217. /****************************************************************************
  218. Callback function that executes whenever character data is encountered
  219. while being parsed.
  220. * @param $parser int. The handle to the parser.
  221. * @param $data string. Character data inside the tag
  222. * @returns void
  223. ****************************************************************************/
  224. function handleCharacterData($parser, $data)
  225. {
  226. $tagHandler = isset($this->tagHandlers[$this->getCurrentTag()]) ? $this->tagHandlers[$this->getCurrentTag()] : null;
  227. if (null != $tagHandler && is_subclass_of($tagHandler, 'xmltaghandler')) {
  228. $tagHandler->handleCharacterData($this, $data);
  229. } else {
  230. $this->handleCharacterDataDefault($parser, $data);
  231. }
  232. }
  233. /**
  234. * @param $parser int. The handle to the parser.
  235. * @param $target
  236. * @param $data
  237. * @return void
  238. */
  239. function handleProcessingInstruction($parser, &$target, &$data)
  240. {
  241. // if($target == 'php') {
  242. // eval($data);
  243. // }
  244. }
  245. /**
  246. * @param $parser
  247. * @param $data
  248. * @return void
  249. */
  250. function handleDefault($parser, $data)
  251. {
  252. }
  253. /**
  254. * @param $parser
  255. * @param $entityName
  256. * @param $base
  257. * @param $systemId
  258. * @param $publicId
  259. * @param $notationName
  260. * @return void
  261. */
  262. function handleUnparsedEntityDecl($parser, $entityName, $base, $systemId, $publicId, $notationName)
  263. {
  264. }
  265. /**
  266. * @param $parser
  267. * @param $notationName
  268. * @param $base
  269. * @param $systemId
  270. * @param $publicId
  271. * @return void
  272. */
  273. function handleNotationDecl($parser, $notationName, $base, $systemId, $publicId)
  274. {
  275. }
  276. /**
  277. * @param $parser
  278. * @param $openEntityNames
  279. * @param $base
  280. * @param $systemId
  281. * @param $publicId
  282. * @return void
  283. */
  284. function handleExternalEntityRef($parser, $openEntityNames, $base, $systemId, $publicId)
  285. {
  286. }
  287. /**
  288. * The default tag handler method for a tag with no handler
  289. *
  290. * @param $parser
  291. * @param $tagName
  292. * @param $attributesArray
  293. * @return void
  294. */
  295. function handleBeginElementDefault($parser, $tagName, $attributesArray)
  296. {
  297. }
  298. /**
  299. * The default tag handler method for a tag with no handler
  300. *
  301. * @param $parser
  302. * @param $tagName
  303. * @return void
  304. */
  305. function handleEndElementDefault($parser, $tagName)
  306. {
  307. }
  308. /**
  309. * The default tag handler method for a tag with no handler
  310. *
  311. * @abstract
  312. *
  313. * @param $parser
  314. * @param $data
  315. * @return void
  316. */
  317. function handleCharacterDataDefault($parser, $data)
  318. {
  319. }
  320. /**
  321. * Sets error messages
  322. *
  323. * @param $error string an error message
  324. */
  325. function setErrors($error)
  326. {
  327. $this->errors[] = trim($error);
  328. }
  329. /**
  330. * Gets all the error messages
  331. *
  332. * @param $ashtml bool return as html?
  333. * @return mixed
  334. */
  335. function getErrors($ashtml = true)
  336. {
  337. if (!$ashtml) {
  338. return $this->errors;
  339. } else {
  340. $ret = '';
  341. if (count($this->errors) > 0) {
  342. foreach ($this->errors as $error) {
  343. $ret .= $error . '<br />';
  344. }
  345. }
  346. return $ret;
  347. }
  348. }
  349. }