PageRenderTime 43ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/Varien/Simplexml/Element.php

https://gitlab.com/LisovyiEvhenii/ismextensions
PHP | 635 lines | 439 code | 35 blank | 161 comment | 41 complexity | e9de0071cbe5df249b847d9d22473519 MD5 | raw file
  1. <?php
  2. /**
  3. * Magento
  4. *
  5. * NOTICE OF LICENSE
  6. *
  7. * This source file is subject to the Open Software License (OSL 3.0)
  8. * that is bundled with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://opensource.org/licenses/osl-3.0.php
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@magento.com so we can send you a copy immediately.
  14. *
  15. * DISCLAIMER
  16. *
  17. * Do not edit or add to this file if you wish to upgrade Magento to newer
  18. * versions in the future. If you wish to customize Magento for your
  19. * needs please refer to http://www.magento.com for more information.
  20. *
  21. * @category Varien
  22. * @package Varien_Simplexml
  23. * @copyright Copyright (c) 2006-2016 X.commerce, Inc. and affiliates (http://www.magento.com)
  24. * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
  25. */
  26. /**
  27. * Extends SimpleXML to add valuable functionality to SimpleXMLElement class
  28. *
  29. * @category Varien
  30. * @package Varien_Simplexml
  31. * @author Magento Core Team <core@magentocommerce.com>
  32. */
  33. class Varien_Simplexml_Element extends SimpleXMLElement
  34. {
  35. /**
  36. * Would keep reference to parent node
  37. *
  38. * If SimpleXMLElement would support complicated attributes
  39. *
  40. * @todo make use of spl_object_hash to keep global array of simplexml elements
  41. * to emulate complicated attributes
  42. * @var Varien_Simplexml_Element
  43. */
  44. protected $_parent = null;
  45. /**
  46. * For future use
  47. *
  48. * @param Varien_Simplexml_Element $element
  49. */
  50. public function setParent($element)
  51. {
  52. #$this->_parent = $element;
  53. }
  54. /**
  55. * Returns parent node for the element
  56. *
  57. * Currently using xpath
  58. *
  59. * @return Varien_Simplexml_Element
  60. */
  61. public function getParent()
  62. {
  63. if (!empty($this->_parent)) {
  64. $parent = $this->_parent;
  65. } else {
  66. $arr = $this->xpath('..');
  67. $parent = $arr[0];
  68. }
  69. return $parent;
  70. }
  71. /**
  72. * Enter description here...
  73. *
  74. * @return boolean
  75. */
  76. public function hasChildren()
  77. {
  78. if (!$this->children()) {
  79. return false;
  80. }
  81. // simplexml bug: @attributes is in children() but invisible in foreach
  82. foreach ($this->children() as $k=>$child) {
  83. return true;
  84. }
  85. return false;
  86. }
  87. /**
  88. * Returns attribute value by attribute name
  89. *
  90. * @return string
  91. */
  92. public function getAttribute($name){
  93. $attrs = $this->attributes();
  94. return isset($attrs[$name]) ? (string)$attrs[$name] : null;
  95. }
  96. /*
  97. public function addAttribute($name, $value=null, $namespace=null)
  98. {
  99. if (is_null($value)) {
  100. return parent::addAttribute($name);
  101. } else {
  102. if (!is_null($value)) {
  103. $value = $this->xmlentities($value);
  104. }
  105. if (!is_null($namespace)) {
  106. return parent::addAttribute($name, $value, $namespace);
  107. } else {
  108. return parent::addAttribute($name, $value);
  109. }
  110. }
  111. }
  112. public function addChild($name, $value=null, $namespace=null)
  113. {
  114. if (is_null($value)) {
  115. return parent::addChild($name);
  116. } else {
  117. if (!is_null($value)) {
  118. $value = $this->xmlentities($value);
  119. }
  120. if (!is_null($namespace)) {
  121. return parent::addChild($name, $value, $namespace);
  122. } else {
  123. return parent::addChild($name, $value);
  124. }
  125. }
  126. }
  127. */
  128. /**
  129. * Find a descendant of a node by path
  130. *
  131. * @todo Do we need to make it xpath look-a-like?
  132. * @todo Check if we still need all this and revert to plain XPath if this makes any sense
  133. * @todo param string $path Subset of xpath. Example: "child/grand[@attrName='attrValue']/subGrand"
  134. * @param string $path Example: "child/grand@attrName=attrValue/subGrand" (to make it faster without regex)
  135. * @return Varien_Simplexml_Element
  136. */
  137. public function descend($path)
  138. {
  139. # $node = $this->xpath($path);
  140. # return $node[0];
  141. if (is_array($path)) {
  142. $pathArr = $path;
  143. } else {
  144. // Simple exploding by / does not suffice,
  145. // as an attribute value may contain a / inside
  146. // Note that there are three matches for different kinds of attribute values specification
  147. if(strpos($path, "@") === false) {
  148. $pathArr = explode('/', $path);
  149. }
  150. else {
  151. $regex = "#([^@/\\\"]+(?:@[^=/]+=(?:\\\"[^\\\"]*\\\"|[^/]*))?)/?#";
  152. $pathArr = $pathMatches = array();
  153. if(preg_match_all($regex, $path, $pathMatches)) {
  154. $pathArr = $pathMatches[1];
  155. }
  156. }
  157. }
  158. $desc = $this;
  159. foreach ($pathArr as $nodeName) {
  160. if (strpos($nodeName, '@')!==false) {
  161. $a = explode('@', $nodeName);
  162. $b = explode('=', $a[1]);
  163. $nodeName = $a[0];
  164. $attributeName = $b[0];
  165. $attributeValue = $b[1];
  166. //
  167. // Does a very simplistic trimming of attribute value.
  168. //
  169. $attributeValue = trim($attributeValue, '"');
  170. $found = false;
  171. foreach ($desc->$nodeName as $subdesc) {
  172. if ((string)$subdesc[$attributeName]===$attributeValue) {
  173. $found = true;
  174. $desc = $subdesc;
  175. break;
  176. }
  177. }
  178. if (!$found) {
  179. $desc = false;
  180. }
  181. } else {
  182. $desc = $desc->$nodeName;
  183. }
  184. if (!$desc) {
  185. return false;
  186. }
  187. }
  188. return $desc;
  189. }
  190. /**
  191. * Returns the node and children as an array
  192. *
  193. * @return array|string
  194. */
  195. public function asArray()
  196. {
  197. return $this->_asArray();
  198. }
  199. /**
  200. * asArray() analog, but without attributes
  201. * @return array|string
  202. */
  203. public function asCanonicalArray()
  204. {
  205. return $this->_asArray(true);
  206. }
  207. /**
  208. * Returns the node and children as an array
  209. *
  210. * @param bool $isCanonical - whether to ignore attributes
  211. * @return array|string
  212. */
  213. protected function _asArray($isCanonical = false)
  214. {
  215. $result = array();
  216. if (!$isCanonical) {
  217. // add attributes
  218. foreach ($this->attributes() as $attributeName => $attribute) {
  219. if ($attribute) {
  220. $result['@'][$attributeName] = (string)$attribute;
  221. }
  222. }
  223. }
  224. // add children values
  225. if ($this->hasChildren()) {
  226. foreach ($this->children() as $childName => $child) {
  227. $result[$childName] = $child->_asArray($isCanonical);
  228. }
  229. } else {
  230. if (empty($result)) {
  231. // return as string, if nothing was found
  232. $result = (string) $this;
  233. } else {
  234. // value has zero key element
  235. $result[0] = (string) $this;
  236. }
  237. }
  238. return $result;
  239. }
  240. /**
  241. * Makes nicely formatted XML from the node
  242. *
  243. * @param string $filename
  244. * @param int|boolean $level if false
  245. * @return string
  246. */
  247. public function asNiceXml($filename='', $level=0)
  248. {
  249. if (is_numeric($level)) {
  250. $pad = str_pad('', $level*3, ' ', STR_PAD_LEFT);
  251. $nl = "\n";
  252. } else {
  253. $pad = '';
  254. $nl = '';
  255. }
  256. $out = $pad.'<'.$this->getName();
  257. if ($attributes = $this->attributes()) {
  258. foreach ($attributes as $key=>$value) {
  259. $out .= ' '.$key.'="'.str_replace('"', '\"', (string)$value).'"';
  260. }
  261. }
  262. if ($this->hasChildren()) {
  263. $out .= '>'.$nl;
  264. foreach ($this->children() as $child) {
  265. $out .= $child->asNiceXml('', is_numeric($level) ? $level+1 : true);
  266. }
  267. $out .= $pad.'</'.$this->getName().'>'.$nl;
  268. } else {
  269. $value = (string)$this;
  270. if (strlen($value)) {
  271. $out .= '>'.$this->xmlentities($value).'</'.$this->getName().'>'.$nl;
  272. } else {
  273. $out .= '/>'.$nl;
  274. }
  275. }
  276. if ((0===$level || false===$level) && !empty($filename)) {
  277. file_put_contents($filename, $out);
  278. }
  279. return $out;
  280. }
  281. /**
  282. * Enter description here...
  283. *
  284. * @param int $level
  285. * @return string
  286. */
  287. public function innerXml($level=0)
  288. {
  289. $out = '';
  290. foreach ($this->children() as $child) {
  291. $out .= $child->asNiceXml($level);
  292. }
  293. return $out;
  294. }
  295. /**
  296. * Converts meaningful xml characters to xml entities
  297. *
  298. * @param string
  299. * @return string
  300. */
  301. public function xmlentities($value = null)
  302. {
  303. if (is_null($value)) {
  304. $value = $this;
  305. }
  306. $value = (string)$value;
  307. $value = str_replace(
  308. array('&', '"', "'", '<', '>'),
  309. array('&amp;', '&quot;', '&apos;', '&lt;', '&gt;'),
  310. $value
  311. );
  312. return $value;
  313. }
  314. /**
  315. * Appends $source to current node
  316. *
  317. * @param Varien_Simplexml_Element $source
  318. * @return Varien_Simplexml_Element
  319. */
  320. public function appendChild($source)
  321. {
  322. if ($source->children()) {
  323. /**
  324. * @see http://bugs.php.net/bug.php?id=41867 , fixed in 5.2.4
  325. */
  326. if (version_compare(phpversion(), '5.2.4', '<')===true) {
  327. $name = $source->children()->getName();
  328. }
  329. else {
  330. $name = $source->getName();
  331. }
  332. $child = $this->addChild($name);
  333. } else {
  334. $child = $this->addChild($source->getName(), $this->xmlentities($source));
  335. }
  336. $child->setParent($this);
  337. $attributes = $source->attributes();
  338. foreach ($attributes as $key=>$value) {
  339. $child->addAttribute($key, $this->xmlentities($value));
  340. }
  341. foreach ($source->children() as $sourceChild) {
  342. $child->appendChild($sourceChild);
  343. }
  344. return $this;
  345. }
  346. /**
  347. * Extends current node with xml from $source
  348. *
  349. * If $overwrite is false will merge only missing nodes
  350. * Otherwise will overwrite existing nodes
  351. *
  352. * @param Varien_Simplexml_Element $source
  353. * @param boolean $overwrite
  354. * @return Varien_Simplexml_Element
  355. */
  356. public function extend($source, $overwrite=false)
  357. {
  358. if (!$source instanceof Varien_Simplexml_Element) {
  359. return $this;
  360. }
  361. foreach ($source->children() as $child) {
  362. $this->extendChild($child, $overwrite);
  363. }
  364. return $this;
  365. }
  366. /**
  367. * Extends one node
  368. *
  369. * @param Varien_Simplexml_Element $source
  370. * @param boolean $overwrite
  371. * @return Varien_Simplexml_Element
  372. */
  373. public function extendChild($source, $overwrite=false)
  374. {
  375. // this will be our new target node
  376. $targetChild = null;
  377. // name of the source node
  378. $sourceName = $source->getName();
  379. // here we have children of our source node
  380. $sourceChildren = $source->children();
  381. if (!$source->hasChildren()) {
  382. // handle string node
  383. if (isset($this->$sourceName)) {
  384. // if target already has children return without regard
  385. if ($this->$sourceName->hasChildren()) {
  386. return $this;
  387. }
  388. if ($overwrite) {
  389. unset($this->$sourceName);
  390. } else {
  391. return $this;
  392. }
  393. }
  394. $targetChild = $this->addChild($sourceName, $source->xmlentities());
  395. $targetChild->setParent($this);
  396. foreach ($source->attributes() as $key=>$value) {
  397. $targetChild->addAttribute($key, $this->xmlentities($value));
  398. }
  399. return $this;
  400. }
  401. if (isset($this->$sourceName)) {
  402. $targetChild = $this->$sourceName;
  403. }
  404. if (is_null($targetChild)) {
  405. // if child target is not found create new and descend
  406. $targetChild = $this->addChild($sourceName);
  407. $targetChild->setParent($this);
  408. foreach ($source->attributes() as $key=>$value) {
  409. $targetChild->addAttribute($key, $this->xmlentities($value));
  410. }
  411. }
  412. // finally add our source node children to resulting new target node
  413. foreach ($sourceChildren as $childKey=>$childNode) {
  414. $targetChild->extendChild($childNode, $overwrite);
  415. }
  416. return $this;
  417. }
  418. public function setNode($path, $value, $overwrite=true)
  419. {
  420. $arr1 = explode('/', $path);
  421. $arr = array();
  422. foreach ($arr1 as $v) {
  423. if (!empty($v)) $arr[] = $v;
  424. }
  425. $last = sizeof($arr)-1;
  426. $node = $this;
  427. foreach ($arr as $i=>$nodeName) {
  428. if ($last===$i) {
  429. /*
  430. if (isset($xml->$nodeName)) {
  431. if ($overwrite) {
  432. unset($xml->$nodeName);
  433. } else {
  434. continue;
  435. }
  436. }
  437. $xml->addChild($nodeName, $xml->xmlentities($value));
  438. */
  439. if (!isset($node->$nodeName) || $overwrite) {
  440. // http://bugs.php.net/bug.php?id=36795
  441. // comment on [8 Feb 8:09pm UTC]
  442. if (isset($node->$nodeName) && (version_compare(phpversion(), '5.2.6', '<')===true)) {
  443. $node->$nodeName = $node->xmlentities($value);
  444. } else {
  445. $node->$nodeName = $value;
  446. }
  447. }
  448. } else {
  449. if (!isset($node->$nodeName)) {
  450. $node = $node->addChild($nodeName);
  451. } else {
  452. $node = $node->$nodeName;
  453. }
  454. }
  455. }
  456. return $this;
  457. }
  458. /*
  459. public function extendChildByNode($source, $overwrite=false, $mergeBy='name')
  460. {
  461. // this will be our new target node
  462. $targetChild = null;
  463. // name of the source node
  464. $sourceName = $source->getName();
  465. // here we have children of our source node
  466. $sourceChildren = $source->children();
  467. if (!$sourceChildren) {
  468. // handle string node
  469. if (isset($this->$sourceName)) {
  470. if ($overwrite) {
  471. unset($this->$sourceName);
  472. } else {
  473. return $this;
  474. }
  475. }
  476. $targetChild = $this->addChild($sourceName, (string)$source);
  477. foreach ($source->attributes() as $key=>$value) {
  478. $targetChild->addAttribute($key, $value);
  479. }
  480. return $this;
  481. }
  482. if (isset($this->$sourceName)) {
  483. // search for target child with same name subnode as node's name
  484. if (isset($source->$mergeBy)) {
  485. foreach ($this->$sourceName as $targetNode) {
  486. if (!isset($targetNode->$mergeBy)) {
  487. Zend::exception("Can't merge identified node with non identified");
  488. }
  489. if ((string)$source->$mergeBy==(string)$targetNode->$mergeBy) {
  490. $targetChild = $targetNode;
  491. break;
  492. }
  493. }
  494. } else {
  495. $existsWithId = false;
  496. foreach ($this->$sourceName as $targetNode) {
  497. if (isset($targetNode->$mergeBy)) {
  498. Zend::exception("Can't merge identified node with non identified");
  499. }
  500. }
  501. $targetChild = $this->$sourceName;
  502. }
  503. }
  504. if (is_null($targetChild)) {
  505. // if child target is not found create new and descend
  506. $targetChild = $this->addChild($sourceName);
  507. foreach ($source->attributes() as $key=>$value) {
  508. $targetChild->addAttribute($key, $value);
  509. }
  510. }
  511. // finally add our source node children to resulting new target node
  512. foreach ($sourceChildren as $childKey=>$childNode) {
  513. $targetChild->extendChildByNode($childNode, $overwrite, $mergeBy);
  514. }
  515. return $this;
  516. }
  517. public function extendChildByAttribute($source, $overwrite=false, $mergeBy='name')
  518. {
  519. // this will be our new target node
  520. $targetChild = null;
  521. // name of the source node
  522. $sourceName = $source->getName();
  523. // here we have children of our source node
  524. $sourceChildren = $source->children();
  525. if (!$sourceChildren) {
  526. // handle string node
  527. if (isset($this->$sourceName)) {
  528. if ($overwrite) {
  529. unset($this->$sourceName);
  530. } else {
  531. return $this;
  532. }
  533. }
  534. $targetChild = $this->addChild($sourceName, (string)$source);
  535. foreach ($source->attributes() as $key=>$value) {
  536. $targetChild->addAttribute($key, $value);
  537. }
  538. return $this;
  539. }
  540. if (isset($this->$sourceName)) {
  541. // search for target child with same name subnode as node's name
  542. if (isset($source[$mergeBy])) {
  543. foreach ($this->$sourceName as $targetNode) {
  544. if (!isset($targetNode[$mergeBy])) {
  545. Zend::exception("Can't merge identified node with non identified");
  546. }
  547. if ((string)$source[$mergeBy]==(string)$targetNode[$mergeBy]) {
  548. $targetChild = $targetNode;
  549. break;
  550. }
  551. }
  552. } else {
  553. $existsWithId = false;
  554. foreach ($this->$sourceName as $targetNode) {
  555. if (isset($targetNode[$mergeBy])) {
  556. Zend::exception("Can't merge identified node with non identified");
  557. }
  558. }
  559. $targetChild = $this->$sourceName;
  560. }
  561. }
  562. if (is_null($targetChild)) {
  563. // if child target is not found create new and descend
  564. $targetChild = $this->addChild($sourceName);
  565. foreach ($source->attributes() as $key=>$value) {
  566. $targetChild->addAttribute($key, $value);
  567. }
  568. }
  569. // finally add our source node children to resulting new target node
  570. foreach ($sourceChildren as $childKey=>$childNode) {
  571. $targetChild->extendChildByAttribute($childNode, $overwrite, $mergeBy);
  572. }
  573. return $this;
  574. }
  575. */
  576. }