XMLParser.php 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. <?php
  2. /**
  3. * PEAR_XMLParser
  4. *
  5. * PHP versions 4 and 5
  6. *
  7. * @category pear
  8. * @package PEAR
  9. * @author Greg Beaver <cellog@php.net>
  10. * @author Stephan Schmidt (original XML_Unserializer code)
  11. * @copyright 1997-2009 The Authors
  12. * @license http://opensource.org/licenses/bsd-license New BSD License
  13. * @link http://pear.php.net/package/PEAR
  14. * @since File available since Release 1.4.0a1
  15. */
  16. /**
  17. * Parser for any xml file
  18. * @category pear
  19. * @package PEAR
  20. * @author Greg Beaver <cellog@php.net>
  21. * @author Stephan Schmidt (original XML_Unserializer code)
  22. * @copyright 1997-2009 The Authors
  23. * @license http://opensource.org/licenses/bsd-license New BSD License
  24. * @version Release: 1.10.10
  25. * @link http://pear.php.net/package/PEAR
  26. * @since Class available since Release 1.4.0a1
  27. */
  28. class PEAR_XMLParser
  29. {
  30. /**
  31. * unserilialized data
  32. * @var string $_serializedData
  33. */
  34. var $_unserializedData = null;
  35. /**
  36. * name of the root tag
  37. * @var string $_root
  38. */
  39. var $_root = null;
  40. /**
  41. * stack for all data that is found
  42. * @var array $_dataStack
  43. */
  44. var $_dataStack = array();
  45. /**
  46. * stack for all values that are generated
  47. * @var array $_valStack
  48. */
  49. var $_valStack = array();
  50. /**
  51. * current tag depth
  52. * @var int $_depth
  53. */
  54. var $_depth = 0;
  55. /**
  56. * The XML encoding to use
  57. * @var string $encoding
  58. */
  59. var $encoding = 'ISO-8859-1';
  60. /**
  61. * @return array
  62. */
  63. function getData()
  64. {
  65. return $this->_unserializedData;
  66. }
  67. /**
  68. * @param string xml content
  69. * @return true|PEAR_Error
  70. */
  71. function parse($data)
  72. {
  73. if (!extension_loaded('xml')) {
  74. include_once 'PEAR.php';
  75. return PEAR::raiseError("XML Extension not found", 1);
  76. }
  77. $this->_dataStack = $this->_valStack = array();
  78. $this->_depth = 0;
  79. if (
  80. strpos($data, 'encoding="UTF-8"')
  81. || strpos($data, 'encoding="utf-8"')
  82. || strpos($data, "encoding='UTF-8'")
  83. || strpos($data, "encoding='utf-8'")
  84. ) {
  85. $this->encoding = 'UTF-8';
  86. }
  87. $xp = xml_parser_create($this->encoding);
  88. xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, 0);
  89. xml_set_object($xp, $this);
  90. xml_set_element_handler($xp, 'startHandler', 'endHandler');
  91. xml_set_character_data_handler($xp, 'cdataHandler');
  92. if (!xml_parse($xp, $data)) {
  93. $msg = xml_error_string(xml_get_error_code($xp));
  94. $line = xml_get_current_line_number($xp);
  95. xml_parser_free($xp);
  96. include_once 'PEAR.php';
  97. return PEAR::raiseError("XML Error: '$msg' on line '$line'", 2);
  98. }
  99. xml_parser_free($xp);
  100. return true;
  101. }
  102. /**
  103. * Start element handler for XML parser
  104. *
  105. * @access private
  106. * @param object $parser XML parser object
  107. * @param string $element XML element
  108. * @param array $attribs attributes of XML tag
  109. * @return void
  110. */
  111. function startHandler($parser, $element, $attribs)
  112. {
  113. $this->_depth++;
  114. $this->_dataStack[$this->_depth] = null;
  115. $val = array(
  116. 'name' => $element,
  117. 'value' => null,
  118. 'type' => 'string',
  119. 'childrenKeys' => array(),
  120. 'aggregKeys' => array()
  121. );
  122. if (count($attribs) > 0) {
  123. $val['children'] = array();
  124. $val['type'] = 'array';
  125. $val['children']['attribs'] = $attribs;
  126. }
  127. array_push($this->_valStack, $val);
  128. }
  129. /**
  130. * post-process data
  131. *
  132. * @param string $data
  133. * @param string $element element name
  134. */
  135. function postProcess($data, $element)
  136. {
  137. return trim($data);
  138. }
  139. /**
  140. * End element handler for XML parser
  141. *
  142. * @access private
  143. * @param object XML parser object
  144. * @param string
  145. * @return void
  146. */
  147. function endHandler($parser, $element)
  148. {
  149. $value = array_pop($this->_valStack);
  150. $data = $this->postProcess($this->_dataStack[$this->_depth], $element);
  151. // adjust type of the value
  152. switch (strtolower($value['type'])) {
  153. // unserialize an array
  154. case 'array':
  155. if ($data !== '') {
  156. $value['children']['_content'] = $data;
  157. }
  158. $value['value'] = isset($value['children']) ? $value['children'] : array();
  159. break;
  160. /*
  161. * unserialize a null value
  162. */
  163. case 'null':
  164. $data = null;
  165. break;
  166. /*
  167. * unserialize any scalar value
  168. */
  169. default:
  170. settype($data, $value['type']);
  171. $value['value'] = $data;
  172. break;
  173. }
  174. $parent = array_pop($this->_valStack);
  175. if ($parent === null) {
  176. $this->_unserializedData = &$value['value'];
  177. $this->_root = &$value['name'];
  178. return true;
  179. }
  180. // parent has to be an array
  181. if (!isset($parent['children']) || !is_array($parent['children'])) {
  182. $parent['children'] = array();
  183. if ($parent['type'] != 'array') {
  184. $parent['type'] = 'array';
  185. }
  186. }
  187. if (!empty($value['name'])) {
  188. // there already has been a tag with this name
  189. if (in_array($value['name'], $parent['childrenKeys'])) {
  190. // no aggregate has been created for this tag
  191. if (!in_array($value['name'], $parent['aggregKeys'])) {
  192. if (isset($parent['children'][$value['name']])) {
  193. $parent['children'][$value['name']] = array($parent['children'][$value['name']]);
  194. } else {
  195. $parent['children'][$value['name']] = array();
  196. }
  197. array_push($parent['aggregKeys'], $value['name']);
  198. }
  199. array_push($parent['children'][$value['name']], $value['value']);
  200. } else {
  201. $parent['children'][$value['name']] = &$value['value'];
  202. array_push($parent['childrenKeys'], $value['name']);
  203. }
  204. } else {
  205. array_push($parent['children'],$value['value']);
  206. }
  207. array_push($this->_valStack, $parent);
  208. $this->_depth--;
  209. }
  210. /**
  211. * Handler for character data
  212. *
  213. * @access private
  214. * @param object XML parser object
  215. * @param string CDATA
  216. * @return void
  217. */
  218. function cdataHandler($parser, $cdata)
  219. {
  220. $this->_dataStack[$this->_depth] .= $cdata;
  221. }
  222. }