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

/system/core/core.xmlparser.php

https://github.com/danboy/Croissierd
PHP | 327 lines | 196 code | 60 blank | 71 comment | 28 complexity | e334c8aeb4a4b5155724ac9eba8014a1 MD5 | raw file
  1. <?php
  2. /*
  3. =====================================================
  4. ExpressionEngine - by EllisLab
  5. -----------------------------------------------------
  6. http://expressionengine.com/
  7. -----------------------------------------------------
  8. Copyright (c) 2003 - 2010 EllisLab, Inc.
  9. =====================================================
  10. THIS IS COPYRIGHTED SOFTWARE
  11. PLEASE READ THE LICENSE AGREEMENT
  12. http://expressionengine.com/docs/license.html
  13. =====================================================
  14. File: core.xmlparser.php
  15. -----------------------------------------------------
  16. Purpose: XML parsing functions
  17. =====================================================
  18. */
  19. if ( ! defined('EXT'))
  20. {
  21. exit('Invalid file request');
  22. }
  23. /* -------------------------------------
  24. /* XML_Cache class - holds parsed XML object
  25. /* -------------------------------------*/
  26. class XML_Cache {
  27. var $tag;
  28. var $attributes;
  29. var $value;
  30. var $children;
  31. }
  32. /* -------------------------------------
  33. /* XMLparser class contains all of the
  34. /* methods for handling XML data
  35. /* -------------------------------------*/
  36. class EE_XMLparser {
  37. var $tagdata;
  38. var $index;
  39. var $errors = array();
  40. var $encoding = ''; // 'ISO-8859-1', 'UTF-8', or 'US-ASCII' - empty string should auto-detect
  41. /** -------------------------------------
  42. /** Parse the XML data into an array
  43. /** -------------------------------------*/
  44. function parse_xml($xml)
  45. {
  46. // PHP's XML array structures stink so make our own
  47. if ($this->parse_into_struct($xml) === FALSE)
  48. {
  49. error_log('Unable to parse XML data');
  50. return FALSE;
  51. }
  52. else
  53. {
  54. $elements = array();
  55. $child = array();
  56. foreach ($this->tagdata as $item)
  57. {
  58. $current = count($elements);
  59. if ($item['type'] == 'open' OR $item['type'] == 'complete')
  60. {
  61. $elements[$current] = new XML_Cache;
  62. $elements[$current]->tag = $item['tag'];
  63. $elements[$current]->attributes = (array_key_exists('attributes', $item)) ? $item['attributes'] : '';
  64. $elements[$current]->value = (array_key_exists('value', $item)) ? $item['value'] : '';
  65. /** -------------------------------------
  66. /** Create a new child layer for 'open'
  67. /** -------------------------------------*/
  68. if ($item['type'] == "open")
  69. {
  70. $elements[$current]->children = array();
  71. $child[count($child)] = &$elements;
  72. $elements = &$elements[$current]->children;
  73. }
  74. }
  75. /** -------------------------------------
  76. /** Put child layer into root object
  77. /** -------------------------------------*/
  78. elseif ($item['type'] == 'close')
  79. {
  80. $elements = &$child[count($child) - 1];
  81. unset($child[count($child) - 1]);
  82. }
  83. }
  84. }
  85. return $elements[0];
  86. }
  87. /* END */
  88. /** -------------------------------------
  89. /** Deprecated function for converting delimited data to XML
  90. /** -------------------------------------*/
  91. function data2xml($data, $structure, $root = "root", $element = "element", $delimiter = "\t", $enclosure = '')
  92. {
  93. if ( ! is_string($data) OR ! is_array($structure) OR count($structure) == 0)
  94. {
  95. $this->errors[] = "Data or structure improperly defined";
  96. return FALSE;
  97. }
  98. $params = array(
  99. 'data' => $data,
  100. 'structure' => $structure,
  101. 'root' => $root,
  102. 'element' => $element,
  103. 'delimiter' => $delimiter,
  104. 'enclosure' => $enclosure
  105. );
  106. return $this->delimited_to_xml($params);
  107. }
  108. /* END */
  109. /** -------------------------------------
  110. /** Convert delimited text to XML
  111. /** -------------------------------------*/
  112. function delimited_to_xml($params)
  113. {
  114. global $REGX;
  115. if ( ! is_array($params))
  116. {
  117. return FALSE;
  118. }
  119. $defaults = array (
  120. 'data' => NULL,
  121. 'structure' => array(),
  122. 'root' => 'root',
  123. 'element' => 'element',
  124. 'delimiter' => "\t",
  125. 'enclosure' => ''
  126. );
  127. foreach ($defaults as $key => $val)
  128. {
  129. if ( ! isset($params[$key]))
  130. {
  131. $params[$key] = $val;
  132. }
  133. }
  134. extract($params);
  135. /*
  136. $data - string containing delimited data
  137. $structure - array providing a key for $data elements
  138. $root - the root XML document tag name
  139. $element - the tag name for the element used to enclose the tag data
  140. $delimiter - the character delimiting the text, default is \t (tab)
  141. $enclosure - character used to enclose the data, such as " in the case of $data = '"item", "item2", "item3"';
  142. */
  143. if ($data === NULL OR ! is_array($structure) OR count($structure) == 0)
  144. {
  145. return FALSE;
  146. }
  147. /** -------------------------------------
  148. /** Convert delimited text to array
  149. /** -------------------------------------*/
  150. $data_arr = array();
  151. $data = preg_replace("/(\015\012)|(\015)|(\012)/", "\n", $data);
  152. $lines = explode("\n", $data);
  153. if (empty($lines))
  154. {
  155. $this->errors[] = "No data to work with";
  156. return FALSE;
  157. }
  158. if ($enclosure == '')
  159. {
  160. foreach ($lines as $key => $val)
  161. {
  162. if ( ! empty($val))
  163. $data_arr[$key] = explode($delimiter, $val);
  164. }
  165. }
  166. else // values are enclosed by a character, e.g.: "value","value2","value3"
  167. {
  168. foreach ($lines as $key => $val)
  169. {
  170. if ( ! empty($val))
  171. {
  172. preg_match_all("/".preg_quote($enclosure)."(.*?)".preg_quote($enclosure)."/si", $val, $matches);
  173. $data_arr[$key] = $matches[1];
  174. if (empty($data_arr[$key]))
  175. {
  176. $this->errors[] = 'Structure mismatch, skipping line: '.$val;
  177. unset($data_arr[$key]);
  178. }
  179. }
  180. }
  181. }
  182. /** -------------------------------------
  183. /** Construct the XML
  184. /** -------------------------------------*/
  185. $xml = "<{$root}>\n";
  186. foreach ($data_arr as $datum)
  187. {
  188. if ( ! empty($datum) AND count($datum) == count($structure))
  189. {
  190. $xml .= "\t<{$element}>\n";
  191. foreach ($datum as $key => $val)
  192. {
  193. $xml .= "\t\t<{$structure[$key]}>".$REGX->xml_convert($val)."</{$structure[$key]}>\n";
  194. }
  195. $xml .= "\t</{$element}>\n";
  196. }
  197. else
  198. {
  199. $details = '';
  200. foreach ($datum as $val)
  201. {
  202. $details .= "{$val}, ";
  203. }
  204. $this->errors[] = 'Line does not match structure: '.substr($details, 0, -2);
  205. }
  206. }
  207. $xml .= "</{$root}>\n";
  208. if ( ! stristr($xml, "<{$element}>"))
  209. {
  210. $this->errors[] = "No valid elements to build XML";
  211. return FALSE;
  212. }
  213. return $xml;
  214. }
  215. /* END */
  216. /** -------------------------------------
  217. /** Parse XML into PHP's array structures
  218. /** -------------------------------------*/
  219. function parse_into_struct($xml, $case = FALSE)
  220. {
  221. // use an empty string to trick PHP into doing what it's supposed to do and auto-detect the encoding
  222. $parser = ($this->encoding == '') ? xml_parser_create('') : xml_parser_create($this->encoding);
  223. if ($case === FALSE)
  224. xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
  225. xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
  226. $entities = $this->fetch_entity_definitions($xml);
  227. $xml = ($entities === FALSE) ? $xml : $this->replace_entities($xml, $entities);
  228. if (xml_parse_into_struct($parser, $xml, $this->tagdata, $this->index) === 0)
  229. {
  230. xml_parser_free($parser);
  231. return FALSE;
  232. }
  233. xml_parser_free($parser);
  234. return TRUE;
  235. }
  236. /* END */
  237. /** -------------------------------------
  238. /** Read XML DTD entity definitions
  239. /** -------------------------------------*/
  240. function fetch_entity_definitions($xml)
  241. {
  242. $entities = array();
  243. preg_match_all("/\<\!ENTITY\s*([\w-]+)\s*\"(.+)\"/siU", $xml, $matches);
  244. if (isset($matches[0][0]))
  245. {
  246. $entities[0] = $matches[1];
  247. $entities[1] = $matches[2];
  248. return $entities;
  249. }
  250. return FALSE;
  251. }
  252. /* END */
  253. /** -------------------------------------
  254. /** Replace DTD entities in XML
  255. /** -------------------------------------*/
  256. function replace_entities($xml, $entities)
  257. {
  258. foreach ($entities[0] as $key => $val)
  259. {
  260. $xml = str_replace('&'.$entities[0][$key].';', $entities[1][$key], $xml);
  261. }
  262. return $xml;
  263. }
  264. /* END */
  265. }
  266. /* END */
  267. ?>