PageRenderTime 55ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/components/LZ.PHP.XMLStruct.php

https://github.com/clottery/bloglounge
PHP | 406 lines | 368 code | 35 blank | 3 comment | 102 complexity | 669106b9c7ad4b6bd2701bc241ec98ff MD5 | raw file
Possible License(s): GPL-2.0
  1. <?php
  2. // Copyright of each part belongs its author.
  3. // LZ.XMLStruct class based on XMLStruct class in Eolin.PHP.Core component of TextCube 1.5.
  4. // Tatter Network Foundation / NeedleWorks has all legal rights of Textcube 1.5/ license under GPL.
  5. class XMLStruct {
  6. var $struct, $error;
  7. function XMLStruct() {
  8. $this->ns = array();
  9. $this->nsenabled = true;
  10. }
  11. function getValueByLocale($param) {
  12. if (!is_array($param)) return $param;
  13. for ($i = 0; $i < count($param); $i++) {
  14. $lang = (isset($param[$i]['.attributes']['xml:lang'])) ? $param[$i]['.attributes']['xml:lang'] : '';
  15. switch (Locale::match($lang)) {
  16. case 3:
  17. $matched = $param[$i];
  18. unset($secondBest);
  19. unset($thirdBest);
  20. $i = count($param); // for exit loop
  21. break;
  22. case 2:
  23. $secondBest = $param[$i];
  24. break;
  25. case 1:
  26. $thirdBest = $param[$i];
  27. break;
  28. case 0:
  29. if (!isset($thirdBest))
  30. $thirdBest = $param[$i];
  31. break;
  32. }
  33. }
  34. if (isset($secondBest)) {
  35. $matched = $secondBest;
  36. } else if (isset($thirdBest)) {
  37. $matched = $thirdBest;
  38. }
  39. if (!isset($matched))
  40. return null;
  41. if (isset($matched['.value']))
  42. return str_replace('&amp;','&',$matched['.value']);
  43. return null;
  44. }
  45. function setNameSpacePrefix( $prefix, $url ) {
  46. $this->ns[$prefix] = $url;
  47. }
  48. function expandNS($item) {
  49. if (!$this->nsenabled)
  50. return $item;
  51. foreach ($this->ns as $prefix => $url ) {
  52. if (substr( $item, 0, strlen($prefix) + 1) == "$prefix:" ) {
  53. return "$url:" . substr( $item, strlen($prefix) + 1 );
  54. }
  55. }
  56. return $item;
  57. }
  58. function open($xml, $encoding = null, $nsenabled = false) {
  59. if (!empty($encoding) && (strtolower($encoding) != 'utf-8') && !UTF8::validate($xml)) {
  60. if (preg_match('/^<\?xml[^<]*\s+encoding=["\']?([\w-]+)["\']?/', $xml, $matches)) {
  61. $encoding = $matches[1];
  62. $xml = preg_replace('/^(<\?xml[^<]*\s+encoding=)["\']?[\w-]+["\']?/', '$1"utf-8"', $xml, 1);
  63. }
  64. if (strcasecmp($encoding, 'utf-8')) {
  65. $xml = UTF8::bring($xml, $encoding);
  66. if ($xml === null) {
  67. $this->error = XML_ERROR_UNKNOWN_ENCODING;
  68. return false;
  69. }
  70. }
  71. } else {
  72. if (substr($xml, 0, 3) == "\xEF\xBB\xBF")
  73. $xml = substr($xml, 3);
  74. }
  75. $xml = str_replace('&', '&amp;', $xml); // for parse error code 23 (&)
  76. $this->nsenabled = $nsenabled;
  77. $p = ($nsenabled) ? xml_parser_create_ns() : xml_parser_create();
  78. xml_set_object($p, $this);
  79. xml_parser_set_option($p, XML_OPTION_CASE_FOLDING, 0);
  80. xml_set_element_handler($p, 'o', 'c');
  81. xml_set_character_data_handler($p, 'd');
  82. xml_set_default_handler($p, 'x');
  83. $this->struct = array();
  84. $this->_cursor = &$this->struct;
  85. $this->_path = array('');
  86. $this->_cdata = false;
  87. if (!xml_parse($p, $xml))
  88. return $this->_error($p);
  89. unset($this->_cursor);
  90. unset($this->_cdata);
  91. if (xml_get_error_code($p) != XML_ERROR_NONE)
  92. return $this->_error($p);
  93. xml_parser_free($p);
  94. return true;
  95. }
  96. function openFile($filename, $correct = false) {
  97. if (!$fp = fopen($filename, 'r'))
  98. return false;
  99. $p = xml_parser_create();
  100. xml_set_object($p, $this);
  101. xml_parser_set_option($p, XML_OPTION_CASE_FOLDING, 0);
  102. xml_set_element_handler($p, 'o', 'c');
  103. xml_set_character_data_handler($p, 'd');
  104. xml_set_default_handler($p, 'x');
  105. $this->struct = array();
  106. $this->_cursor = &$this->struct;
  107. $this->_path = array('');
  108. $this->_cdata = false;
  109. if ($correct) {
  110. $remains = '';
  111. while (!feof($fp)) {
  112. $chunk = $remains . fread($fp, 10240);
  113. $remains = '';
  114. if (strlen($chunk) >= 10240) {
  115. for ($c = 1; $c <= 4; $c++) {
  116. switch ($chunk{strlen($chunk) - $c} & "\xC0") {
  117. case "\x00":
  118. case "\x40":
  119. if ($c > 1) {
  120. $remains = substr($chunk, strlen($chunk) - $c + 1);
  121. $chunk = substr($chunk, 0, strlen($chunk) - $c + 1);
  122. }
  123. $c = 5;
  124. break;
  125. case "\xC0":
  126. $remains = substr($chunk, strlen($chunk) - $c);
  127. $chunk = substr($chunk, 0, strlen($chunk) - $c);
  128. $c = 5;
  129. break;
  130. }
  131. }
  132. }
  133. $xml = str_replace('&','&amp;',UTF8::correct($chunk, '?'));
  134. if (!xml_parse($p, $xml, false)) {
  135. fclose($fp);
  136. return $this->_error($p);
  137. }
  138. }
  139. } else {
  140. while (!feof($fp)) {
  141. $xml = str_replace('&','&amp;',fread($fp, 10240));
  142. if (!xml_parse($p, $xml, false)) {
  143. fclose($fp);
  144. return $this->_error($p);
  145. }
  146. }
  147. }
  148. fclose($fp);
  149. if (!xml_parse($p, '', true))
  150. return $this->_error($p);
  151. unset($this->_cursor);
  152. unset($this->_cdata);
  153. if (xml_get_error_code($p) != XML_ERROR_NONE)
  154. return $this->_error($p);
  155. xml_parser_free($p);
  156. return true;
  157. }
  158. function close() {
  159. }
  160. function setStream($path) {
  161. $this->_streams[$path] = true;
  162. }
  163. function setConsumer($consumer) {
  164. $this->_consumer = $consumer;
  165. }
  166. function & selectNode($path, $lang = null) {
  167. $path = explode('/', $path);
  168. if (array_shift($path) != '') {
  169. $null = null;
  170. return $null;
  171. }
  172. $cursor = &$this->struct;
  173. while (is_array($cursor) && ($step = array_shift($path))) {
  174. $step = $this->expandNS($step);
  175. if (!preg_match('/^([^[]+)(\[(\d+|lang\(\))\])?$/', $step, $matches)) {
  176. $null = null;
  177. return $null;
  178. }
  179. $name = $matches[1];
  180. if (!isset($cursor[$name][0])) {
  181. $null = null;
  182. return $null;
  183. }
  184. if (count($matches) != 4) { // Node name only.
  185. if (isset($cursor[$name][0])) {
  186. $cursor = &$cursor[$name][0];
  187. } else {
  188. $null = null;
  189. return $null;
  190. }
  191. } else if ($matches[3] != 'lang()') { // Position.
  192. $index = $matches[3];
  193. $index--;
  194. if (isset($cursor[$name][$index])) {
  195. $cursor = &$cursor[$name][$index];
  196. } else {
  197. $null = null;
  198. return $null;
  199. }
  200. } else { // lang() expression.
  201. for ($i = 0; $i < count($cursor[$name]); $i++) {
  202. $lang = (isset($cursor[$name][$i]['.attributes']['xml:lang'])) ? $cursor[$name][$i]['.attributes']['xml:lang'] : '';
  203. switch (Locale::match($lang)) {
  204. case 3:
  205. $cursor = &$cursor[$name][$i];
  206. return $cursor;
  207. case 2:
  208. $secondBest = &$cursor[$name][$i];
  209. break;
  210. case 1:
  211. $thirdBest = &$cursor[$name][$i];
  212. break;
  213. case 0:
  214. if (!isset($thirdBest))
  215. $thirdBest = &$cursor[$name][$i];
  216. break;
  217. }
  218. }
  219. if (isset($secondBest)) {
  220. $cursor = &$secondBest;
  221. } else if (isset($thirdBest)) {
  222. $cursor = &$thirdBest;
  223. } else {
  224. $null = null;
  225. return $null;
  226. }
  227. }
  228. }
  229. return $cursor;
  230. }
  231. function & selectNodes($path) {
  232. $p = explode('/', $path);
  233. if (array_shift($p) != '') {
  234. $null = null;
  235. return $null;
  236. }
  237. $c = &$this->struct;
  238. while ($d = array_shift($p)) {
  239. $o = 0;
  240. if ($d{strlen($d) - 1} == ']') {
  241. @list($d, $o) = split('\[', $d, 2);
  242. if ($o === null) {
  243. $null = null;
  244. return $null;
  245. }
  246. $o = substr($o, 0, strlen($o) - 1);
  247. if (!is_numeric($o)) {
  248. $null = null;
  249. return $null;
  250. }
  251. $o--;
  252. }
  253. $d = $this->expandNS($d);
  254. if (empty($p)) {
  255. if (isset($c[$d])) {
  256. return $c[$d];
  257. } else {
  258. $null = null;
  259. return $null;
  260. }
  261. }
  262. if (isset($c[$d][$o]))
  263. $c = &$c[$d][$o];
  264. else
  265. break;
  266. }
  267. $null = null;
  268. return $null;
  269. }
  270. function doesExist($path) {
  271. return ($this->selectNode($path) !== null);
  272. }
  273. function getAttribute($path, $name, $default = null) {
  274. $n = &$this->selectNode($path);
  275. if (($n !== null) && isset($n['.attributes'][$name]))
  276. return str_replace('&amp;','&',$n['.attributes'][$name]);
  277. else
  278. return $default;
  279. }
  280. function getAttributes($path, $names) {
  281. if(!is_array($names)) return $this->getAttribute($path, $names);
  282. $n = &$this->selectNode($path);
  283. if ($n !== null) {
  284. $result = array();
  285. $b = 0;
  286. foreach($names as $name) {
  287. if(isset($n['.attributes'][$name])) {
  288. $b ++;
  289. array_push($result, str_replace('&amp;','&',$n['.attributes'][$name]));
  290. } else {
  291. array_push($result, '');
  292. }
  293. }
  294. return ($b>0&&count($result)>0)?$result:null;
  295. }
  296. else
  297. return null;
  298. }
  299. function getValue($path) {
  300. $n = &$this->selectNode($path);
  301. return (isset($n['.value']) ? str_replace('&amp;','&',$n['.value']) : null);
  302. }
  303. function getNodeCount($path) {
  304. return count($this->selectNodes($path));
  305. }
  306. function o($p, $n, $a) {
  307. if (isset($a['http://www.w3.org/XML/1998/namespace:lang']))
  308. $a['xml:lang'] = $a['http://www.w3.org/XML/1998/namespace:lang'];
  309. if (!isset($this->_cursor[$n]))
  310. $this->_cursor[$n] = array();
  311. if (empty($a))
  312. $this->_cursor = &$this->_cursor[$n][array_push($this->_cursor[$n], array('.value' => '', '_' => &$this->_cursor)) - 1];
  313. else
  314. $this->_cursor = &$this->_cursor[$n][array_push($this->_cursor[$n], array('.attributes' => $a, '.value' => '', '_' => &$this->_cursor)) - 1];
  315. $this->_cdata = null;
  316. array_push($this->_path, $n);
  317. if (isset($this->_streams[implode('/', $this->_path)]))
  318. $this->_cursor['.stream'] = tmpfile();
  319. }
  320. function c($p, $n) {
  321. if (count($this->_cursor) != (2 + isset($this->_cursor['.attributes'])))
  322. unset($this->_cursor['.value']);
  323. else
  324. $this->_cursor['.value'] = rtrim($this->_cursor['.value']);
  325. $c = &$this->_cursor;
  326. $this->_cursor = &$this->_cursor['_'];
  327. unset($c['_']);
  328. if (isset($this->_consumer)) {
  329. if (call_user_func($this->_consumer, implode('/', $this->_path), $c, xml_get_current_line_number($p))) {
  330. if (count($this->_cursor[$n]) == 1)
  331. unset($this->_cursor[$n]);
  332. else
  333. array_pop($this->_cursor[$n]);
  334. }
  335. }
  336. array_pop($this->_path);
  337. }
  338. function d($p, $d) {
  339. if (count($this->_cursor) != (1 + isset($this->_cursor['.value']) + isset($this->_cursor['.attributes']) + isset($this->_cursor['.stream'])))
  340. return;
  341. if (!$this->_cdata) {
  342. if (isset($this->_cdata))
  343. $this->_cursor['.value'] = rtrim($this->_cursor['.value']);
  344. $this->_cdata = true;
  345. $d = ltrim($d);
  346. }
  347. if (strlen($d) == 0)
  348. return;
  349. if (empty($this->_cursor['.stream']))
  350. $this->_cursor['.value'] .= $d;
  351. else
  352. fwrite($this->_cursor['.stream'], $d);
  353. }
  354. function x($p, $d) {
  355. if ($d == '<![CDATA[')
  356. $this->_cdata = true;
  357. else if (($d == ']]>') && $this->_cdata)
  358. $this->_cdata = false;
  359. }
  360. function _error($p) {
  361. $this->error = array(
  362. 'code' => xml_get_error_code($p),
  363. 'offset' => xml_get_current_byte_index($p),
  364. 'line' => xml_get_current_line_number($p),
  365. 'column' => xml_get_current_column_number($p)
  366. );
  367. xml_parser_free($p);
  368. return false;
  369. }
  370. }
  371. ?>