PageRenderTime 50ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/com_eve/plugins/system_eve/eve/lib/ale/parser/xmlelement.php

http://joomla-in-eve.googlecode.com/
PHP | 396 lines | 212 code | 32 blank | 152 comment | 42 complexity | 8636cdef796043cc7aebf4364aa5ed30 MD5 | raw file
Possible License(s): LGPL-3.0, GPL-3.0
  1. <?php
  2. /**
  3. * @version $Id: xmlelement.php 215 2010-05-14 20:27:33Z kovalikp $
  4. * @license GNU/LGPL, see COPYING and COPYING.LESSER
  5. * This file is part of Ale - PHP API Library for EVE.
  6. *
  7. * Ale is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU Lesser General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * Ale is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public License
  18. * along with Ale. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. /**
  21. * Wrapper for SimpleXMLElement providing most features of SimpleXML (read only)
  22. * Provides features speciffic for EVE API xml format, namely
  23. * <ul>
  24. * <li>Direct access to rowset nodes by their 'name' attribute</li>
  25. * <li>Array-like access to row nodes for rowsets by their 'key' attribute</li>
  26. * <li>Iteration through row nodes</li>
  27. * <li>Parsing to array structure</li>
  28. * </ul>
  29. *
  30. * @example
  31. * <?php
  32. * $data = $api->char->CharacterSheet(); //get character sheet
  33. * $xml = new AleParserXMLElement($data);
  34. * $cachedUntil = $xml->cachedUntil; //direct acces to node by node name
  35. * $skills = $xml->result->skills; //direct access to rowset node by attribute name
  36. * foreach ($xml->result->skills as $skill) {} //iteration
  37. * $skillCount = count($skills); //number of skills
  38. * $skillArray = $skills->toArray(); //convert node to array
  39. * $skills[3413]->skillpoints; //array-like access to rowset node, 'skillpoinsts' is attribute of row
  40. */
  41. class AleParserXMLElement implements Countable, ArrayAccess, IteratorAggregate {
  42. private $name = null;
  43. private $data = null;
  44. private $children = null;
  45. private $attributes = null;
  46. private $rows = null;
  47. /**
  48. * Constuctor
  49. *
  50. * @param SimpleXMLElement|string $data
  51. */
  52. public function __construct($data) {
  53. if (is_string($data)) {
  54. $data = new SimpleXMLElement($data);
  55. }
  56. if (!($data instanceof SimpleXMLElement)) {
  57. throw new InvalidArgumentException('EveApiParser::__construct(): requires instance of SimpleXMLElement or valid XML string');
  58. }
  59. $this->data = $data;
  60. $this->name = $data->getName();
  61. if (!$this->name) {
  62. return;
  63. }
  64. }
  65. /**
  66. * Prepare child nodes. "rowset" modes will be accesed by their "name" attribute
  67. *
  68. */
  69. protected function prepareChildren() {
  70. if (isset($this->children)) {
  71. return;
  72. }
  73. $this->children = array();
  74. $nodes = $this->data->children();
  75. foreach ($nodes as $node) {
  76. $name = (string) $node->getName();
  77. if ($name == 'rowset') {
  78. $attribs = $node->attributes();
  79. $this->children[(string) $attribs['name']] = $this->transformNode($node);
  80. } else {
  81. $this->children[$name] = $this->transformNode($node);
  82. }
  83. }
  84. $this->attributes = array();
  85. $attribs = $this->data->attributes();
  86. foreach ($attribs as $key => $value) {
  87. $this->attributes[(string) $key] = (string) $value;
  88. }
  89. }
  90. /**
  91. * Prepare rows array attribute for 'rowset' node
  92. *
  93. */
  94. protected function prepareRows() {
  95. if (isset($this->rows)) {
  96. return;
  97. }
  98. $this->rows = array();
  99. if ($this->name == 'rowset') {
  100. $attribs = $this->data->attributes();
  101. $key = isset($attribs['key']) ? (string) $attribs['key'] : null;
  102. $keys = $key ? explode(',', $key) : array();
  103. $children = $this->data->children();
  104. foreach ($children as $child) {
  105. if ($child->getName() != 'row') {
  106. continue;
  107. }
  108. //echo (string)$child;
  109. $child = $this->transformNode($child);
  110. if ($key) {
  111. $attribs = $child->attributes();
  112. $rows = &$this->rows;
  113. for ($i = 0; $i < count($keys); $i++) {
  114. $keyVal = (string) $attribs[trim($keys[$i])];
  115. if ($i == count($keys) - 1) {
  116. $rows[$keyVal] = $child;
  117. } else {
  118. if (!isset($rows[$keyVal])){
  119. $rows[$keyVal] = array();
  120. }
  121. $rows = &$rows[$keyVal];
  122. }
  123. }
  124. } else {
  125. $this->rows[] = $child;
  126. }
  127. }
  128. }
  129. }
  130. /**
  131. * Return instance of same class as "$this"
  132. *
  133. * @param SimpleXMLElement|string $node
  134. * @return AleParserXMLElement
  135. */
  136. protected function transformNode($node) {
  137. $classname = get_class($this);
  138. return new $classname($node);
  139. }
  140. /**
  141. * Walk through node tree and fills $result array
  142. *
  143. * @param array $result
  144. * @param SimpleXMLElement $node
  145. * @param string $key
  146. */
  147. protected function nodeToArray(&$result, $node, $key = null) {
  148. $name = (string) $node->getName();
  149. $attributes = $node->attributes();
  150. $children = $node->children();
  151. if (count($attributes) || count($children)) {
  152. $result = array();
  153. if (!count($children) && (string) $node) {
  154. $result['nodeText'] = (string) $node;
  155. }
  156. } else {
  157. $result = (string) $node;
  158. }
  159. if ($name != 'rowset') {
  160. foreach ($attributes as $aname => $avalue) {
  161. $result[(string)$aname] = (string) $avalue;
  162. }
  163. }
  164. $i = 0;
  165. foreach ($children as $name => $child) {
  166. if (!is_array($result)) {
  167. $result = array();
  168. }
  169. $attributes = $child->attributes();
  170. $_key = $key;
  171. if ($name == 'rowset') {
  172. $name = (string) $attributes['name'];
  173. $_key = (string) $attributes['key'];
  174. }
  175. if ($name == 'row') {
  176. //echo $key.'--';
  177. $keys = $key ? explode(',', $key) : array();
  178. //print_r($keys);
  179. $tmp = &$result;
  180. for ($ii = 0; $ii < count($keys); $ii++) {
  181. $keyVal = (string) $attributes[trim($keys[$ii])];
  182. if ($ii == count($keys) - 1) {
  183. $this->nodeToArray($tmp[$keyVal], $child, $_key);
  184. continue 2;
  185. } else {
  186. if (!isset($tmp[$keyVal])){
  187. $tmp[$keyVal] = array();
  188. }
  189. $tmp =& $tmp[$keyVal];
  190. }
  191. }
  192. $name = (string) $attributes[$key];
  193. if (!$name) {
  194. $name = $i;
  195. }
  196. }
  197. $this->nodeToArray($result[$name], $child, $_key);
  198. $i += 1;
  199. }
  200. }
  201. /**
  202. * Returns data as SimpleXMLElement
  203. *
  204. * @return SimpleXMLElement
  205. */
  206. public function getSimpleXMLElement() {
  207. return $this->data;
  208. }
  209. /**
  210. * Finds children of given node
  211. *
  212. * @return array
  213. */
  214. public function children() {
  215. $nodes = $this->data->children();
  216. $result = array();
  217. foreach ($nodes as $node) {
  218. $result[] = $this->transformNode($node);
  219. }
  220. return $result;
  221. }
  222. /**
  223. * Get node name
  224. *
  225. * @return string
  226. */
  227. public function getName() {
  228. return $this->name;
  229. }
  230. /**
  231. * Return a well-formed XML string based on element
  232. *
  233. * @return string
  234. */
  235. function asXML() {
  236. return $this->data->asXML();
  237. }
  238. /**
  239. * Identifies an element's attributes
  240. *
  241. * @return unknown
  242. */
  243. public function attributes() {
  244. $this->prepareChildren();
  245. return $this->attributes;
  246. }
  247. /**
  248. * The xpath method searches the AleParserXMLElement node for children matching the XPath path.
  249. *
  250. * @param string $path
  251. * @return array
  252. */
  253. public function xpath($path) {
  254. $nodes = $this->data->xpath($path);
  255. $result = array();
  256. foreach ($nodes as $node) {
  257. $result[] = $this->transformNode($node);
  258. }
  259. return $result;
  260. }
  261. /**
  262. * Node accessor
  263. *
  264. * @param string $name
  265. * @return AleParserXMLElement
  266. */
  267. public function __get($name) {
  268. $this->prepareChildren();
  269. if (isset($this->children[$name])) {
  270. return $this->children[$name];
  271. }
  272. if (isset($this->attributes[$name])) {
  273. return $this->attributes[$name];
  274. }
  275. return null;
  276. }
  277. /**
  278. * Node isset checker
  279. *
  280. * @param string $name
  281. * @return AleParserXMLElement
  282. */
  283. public function __isset($name) {
  284. $this->prepareChildren();
  285. return isset($this->children[$name]) || isset($this->attributes[$name]);
  286. }
  287. /**
  288. * Implements ArrayAccess::offsetExists()
  289. *
  290. * @param mixed $i
  291. * @return bool
  292. */
  293. public function offsetExists($i) {
  294. $this->prepareRows();
  295. return isset($this->rows[$i]);
  296. }
  297. /**
  298. * Implements ArrayAccess::offsetGet()
  299. *
  300. * @param mixed $i
  301. * @return AleParserXMLElement
  302. */
  303. public function offsetGet($i) {
  304. $this->prepareRows();
  305. return $this->rows[$i];
  306. }
  307. /**
  308. * Not implemented ArrayAccess::offsetSet()
  309. * Class is read-only
  310. */
  311. public function offsetSet($i, $data) {
  312. throw new BadMethodCallException('Not-Implemented');
  313. }
  314. /**
  315. * Not implemented ArrayAccess::offsetUnset()
  316. * Class is read-only
  317. */
  318. public function offsetUnset($i) {
  319. throw new BadMethodCallException('Not-Implemented');
  320. }
  321. /**
  322. * Implements Countable::count()
  323. * Return number of rows for rowsets
  324. *
  325. * @return int
  326. */
  327. public function count() {
  328. $this->prepareRows();
  329. return count($this->rows);
  330. }
  331. /**
  332. * Implements IteratorAggregate::getIterator()
  333. *
  334. * @return ArrayIterator
  335. */
  336. public function getIterator() {
  337. $this->prepareRows();
  338. return new ArrayIterator($this->rows);
  339. }
  340. /**
  341. * String representation of node
  342. *
  343. * @return string
  344. */
  345. public function __toString() {
  346. return (string) $this->data;
  347. }
  348. /**
  349. * Transform node tree to array structure
  350. *
  351. * @return array
  352. */
  353. public function toArray() {
  354. $key = null;
  355. $name = (string) $this->getName();
  356. if ($name == 'rowset') {
  357. $attributes = $this->attributes();
  358. $key = (string) $attributes['key'];
  359. }
  360. $result = array();
  361. $this->nodeToArray($result, $this->data, $key);
  362. return $result;
  363. }
  364. }