PageRenderTime 47ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/includes/Opl/Opt/Xml/Scannable.php

https://bitbucket.org/kandsten/hitta.sverok.se
PHP | 904 lines | 652 code | 44 blank | 208 comment | 115 complexity | a7051dfe9e5b5890575be144f0b10fc1 MD5 | raw file
Possible License(s): GPL-3.0, MIT
  1. <?php
  2. /*
  3. * OPEN POWER LIBS <http://www.invenzzia.org>
  4. *
  5. * This file is subject to the new BSD license that is bundled
  6. * with this package in the file LICENSE. It is also available through
  7. * WWW at this URL: <http://www.invenzzia.org/license/new-bsd>
  8. *
  9. * Copyright (c) Invenzzia Group <http://www.invenzzia.org>
  10. * and other contributors. See website for details.
  11. *
  12. * $Id: Scannable.php 272 2009-12-23 08:42:26Z zyxist $
  13. */
  14. /**
  15. * The abstract class that represents the XML nodes which can contain
  16. * another nodes. It uses the DOM-like API to manage the nodes.
  17. *
  18. * @abstract
  19. */
  20. class Opt_Xml_Scannable extends Opt_Xml_Node implements Iterator
  21. {
  22. protected $_subnodes;
  23. protected $_i;
  24. protected $_size;
  25. protected $_copy;
  26. private $_prototypes;
  27. /**
  28. * Creates the scannable node.
  29. */
  30. public function __construct()
  31. {
  32. parent::__construct();
  33. } // end __construct();
  34. /*
  35. * Public DOM-like API
  36. */
  37. /**
  38. * Appends a new child to the end of the children list. The method
  39. * is DOM-compatible.
  40. *
  41. * @param Opt_Xml_Node $child The child to be appended.
  42. */
  43. public function appendChild(Opt_Xml_Node $child)
  44. {
  45. // Test if the node can be a child of this and initialize an
  46. // empty array if needed.
  47. $this->_testNode($child);
  48. if(!is_array($this->_subnodes))
  49. {
  50. $this->_subnodes = array();
  51. }
  52. $child->setParent($this);
  53. $this->_subnodes[] = $child;
  54. } // end appendChild();
  55. /**
  56. * Inserts the new node after the node identified by the '$refnode'. The
  57. * reference node can be identified either by the number or by the object.
  58. * If the reference node is empty, the new node is appended to the children
  59. * list, if the last argument allows for that.
  60. *
  61. * @param Opt_Xml_Node $newnode The new node.
  62. * @param Integer|Opt_Xml_Node $refnode The reference node.
  63. * @param Boolean $appendOnError Do we like to append the node, if $refnode does not exist?
  64. */
  65. public function insertBefore(Opt_Xml_Node $newnode, $refnode = null, $appendOnError = true)
  66. {
  67. // Test if the node can be a child of this and initialize an
  68. // empty array if needed.
  69. $this->_testNode($newnode);
  70. if(!is_array($this->_subnodes))
  71. {
  72. $this->_subnodes = array();
  73. }
  74. $newnode->setParent($this);
  75. if(is_null($refnode))
  76. {
  77. $this->_appendChild($newnode, $appendOnError);
  78. }
  79. if(is_object($refnode))
  80. {
  81. $i = 0;
  82. $cnt = sizeof($this->_subnodes);
  83. while($cnt > 0)
  84. {
  85. if(isset($this->_subnodes[$i]))
  86. {
  87. $cnt--;
  88. if($this->_subnodes[$i] === $refnode)
  89. {
  90. $this->_subnodes = $this->_arrayCreateHole($this->_subnodes, $i);
  91. // Opt_Array_Push($this->_subnodes, $i, $cnt);
  92. $this->_subnodes[$i] = $newnode;
  93. break;
  94. }
  95. }
  96. $i++;
  97. }
  98. }
  99. elseif(is_integer($refnode))
  100. {
  101. end($this->_subnodes);
  102. if($refnode <= key($this->_subnodes) && $refnode >= 0)
  103. {
  104. $this->_subnodes = $this->_arrayCreateHole($this->_subnodes, $refnode);
  105. // Opt_Array_Push($this->_subnodes, $refnode);
  106. $this->_subnodes[$refnode] = $newnode;
  107. }
  108. else
  109. {
  110. $this->_appendChild($newnode, $appendOnError);
  111. }
  112. }
  113. } // end insertBefore();
  114. /**
  115. * Removes the child identified either by the number or the object.
  116. *
  117. * @param Integer|Opt_Xml_Node $node The node to be removed.
  118. * @return Boolean
  119. */
  120. public function removeChild($node)
  121. {
  122. if(!is_array($this->_subnodes))
  123. {
  124. return false;
  125. }
  126. if(is_object($node))
  127. {
  128. $cnt = sizeof($this->_subnodes);
  129. $found = 0;
  130. for($i = 0; $i < $cnt; $i++)
  131. {
  132. if(isset($this->_subnodes[$i]))
  133. {
  134. if($this->_subnodes[$i] === $node)
  135. {
  136. $node->setParent(null);
  137. unset($this->_subnodes[$i]);
  138. $found++;
  139. }
  140. }
  141. }
  142. $this->_subnodes = $this->_arrayReduceHoles($this->_subnodes);
  143. return $found > 0;
  144. }
  145. elseif(is_integer($node) && isset($this->_subnodes[$node]))
  146. {
  147. $this->_subnodes[$node]->setParent(null);
  148. // $this->_subnodes[$node]->dispose();
  149. unset($this->_subnodes[$node]);
  150. $this->_subnodes = $this->_arrayReduceHoles($this->_subnodes);
  151. return true;
  152. }
  153. return false;
  154. } // end removeChild();
  155. /**
  156. * Removes all the children. The memory after the children is not freed.
  157. */
  158. public function removeChildren()
  159. {
  160. if(is_array($this->_subnodes))
  161. {
  162. foreach($this->_subnodes as $subnode)
  163. {
  164. if(is_object($subnode))
  165. {
  166. $subnode->setParent(null);
  167. }
  168. }
  169. }
  170. unset($this->_subnodes);
  171. $this->_subnodes = null;
  172. } // end removeChildren();
  173. /**
  174. * Moves all the children of another node to the current node.
  175. *
  176. * @param Opt_Xml_Node $node Another node.
  177. */
  178. public function moveChildren(Opt_Xml_Scannable $node)
  179. {
  180. // If there are already some nodes, we have to free the memory first.
  181. if(is_array($this->_subnodes))
  182. {
  183. foreach($this->_subnodes as $item)
  184. {
  185. if(is_object($item))
  186. {
  187. $item->dispose();
  188. }
  189. }
  190. }
  191. // Move the nodes by copying the internal data structures.
  192. $this->_subnodes = $node->_subnodes;
  193. $this->_i = $node->_i;
  194. $this->_size = $node->_size;
  195. $this->_copy = $node->_copy;
  196. // Reset the children list in the $node.
  197. $node->_subnodes = null;
  198. $node->_i = null;
  199. $node->_size = null;
  200. $node->_copy = null;
  201. // Create a connection between this node and the new children.
  202. if(is_array($this->_subnodes))
  203. {
  204. foreach($this->_subnodes as $subnode)
  205. {
  206. if(is_object($subnode))
  207. {
  208. // Test the node in order to check whether
  209. // we have moved them to the correct node.
  210. $this->_testNode($subnode);
  211. $subnode->setParent($this);
  212. }
  213. }
  214. }
  215. } // end moveChildren();
  216. /**
  217. * Replaces the child with the new node. The reference node can be
  218. * identified either by the number or by the object.
  219. *
  220. * @param Opt_Xml_Node $newnode The new node.
  221. * @param Integer|Opt_Xml_Node $refnode The old node.
  222. * @param Boolean $dispose Dispose the old node?
  223. * @return Boolean
  224. */
  225. public function replaceChild(Opt_Xml_Node $newnode, $refnode, $dispose = false)
  226. {
  227. $this->_testNode($newnode);
  228. if(!is_array($this->_subnodes))
  229. {
  230. return false;
  231. }
  232. $newnode->setParent($this);
  233. if(is_object($refnode))
  234. {
  235. $i = 0;
  236. $cnt = sizeof($this->_subnodes);
  237. while($cnt > 0)
  238. {
  239. if(isset($this->_subnodes[$i]))
  240. {
  241. // SEE: note about comparing" in bringToEnd()
  242. if($refnode === $this->_subnodes[$i])
  243. {
  244. $dispose and $this->_subnodes[$i]->dispose();
  245. $this->_subnodes[$i] = $newnode;
  246. return true;
  247. }
  248. }
  249. $i++;
  250. }
  251. }
  252. elseif(is_integer($refnode) && isset($this->_subnodes[$refnode]))
  253. {
  254. $dispose and $this->_subnodes[$refnode]->dispose();
  255. $this->_subnodes[$refnode] = $newnode;
  256. return true;
  257. }
  258. return false;
  259. } // end replaceChild();
  260. /**
  261. * Returns true, if the current node contains any children.
  262. *
  263. * @return Boolean
  264. */
  265. public function hasChildren()
  266. {
  267. if(!is_array($this->_subnodes))
  268. {
  269. return false;
  270. }
  271. return sizeof($this->_subnodes) > 0;
  272. } // end hasChildren();
  273. /**
  274. * Returns the number of the children.
  275. *
  276. * @return Integer
  277. */
  278. public function countChildren()
  279. {
  280. if(!is_array($this->_subnodes))
  281. {
  282. return 0;
  283. }
  284. return sizeof($this->_subnodes);
  285. } // end countChildren();
  286. /**
  287. * Returns the last child of the node.
  288. *
  289. * @return Opt_Xml_Node
  290. */
  291. public function getLastChild()
  292. {
  293. if(!is_array($this->_subnodes))
  294. {
  295. return NULL;
  296. }
  297. if(sizeof($this->_subnodes) > 0)
  298. {
  299. return end($this->_subnodes);
  300. }
  301. return NULL;
  302. } // end getLastChild();
  303. /**
  304. * Returns the array containing all the children.
  305. *
  306. * @return Array
  307. */
  308. public function getChildren()
  309. {
  310. $cnt = sizeof($this->_subnodes);
  311. $result = array();
  312. for($i = 0; $i < $cnt; $i++)
  313. {
  314. if(is_object($this->_subnodes[$i]))
  315. {
  316. $result[] = $this->_subnodes[$i];
  317. }
  318. }
  319. return $result;
  320. } // end getChildren();
  321. /**
  322. * Returns all the descendants of the current node.
  323. *
  324. * @return Array The list of descendants.
  325. */
  326. public function getElements()
  327. {
  328. $queue = array();
  329. foreach($this->_subnodes as $item)
  330. {
  331. if(is_object($item))
  332. {
  333. $queue[] = $item;
  334. }
  335. }
  336. $result = array();
  337. while(sizeof($queue) > 0)
  338. {
  339. $current = array_shift($queue);
  340. if($current instanceof Opt_Xml_Node)
  341. {
  342. $result[] = $current;
  343. }
  344. if($current instanceof Opt_Xml_Scannable)
  345. {
  346. foreach($current as $subnode)
  347. {
  348. $queue[] = $subnode;
  349. }
  350. }
  351. }
  352. return $result;
  353. } // end getElements();
  354. /**
  355. * Returns all the children or descendants with the specified name.
  356. *
  357. * @param String $name The tag name (without the namespace)
  358. * @param Boolean $recursive Scan the descendants recursively?
  359. * @return Array
  360. */
  361. public function getElementsByTagName($name, $recursive = true)
  362. {
  363. if($recursive)
  364. {
  365. return $this->_getElementsByTagName($name, '*');
  366. }
  367. if(!is_array($this->_subnodes))
  368. {
  369. return array();
  370. }
  371. $result = array();
  372. foreach($this->_subnodes as $subnode)
  373. {
  374. if(!$subnode instanceof Opt_Xml_Element)
  375. {
  376. continue;
  377. }
  378. if($subnode->getName() == $name || $name == '*')
  379. {
  380. $result[] = $subnode;
  381. }
  382. }
  383. return $result;
  384. } // end getElementsByTagName();
  385. /**
  386. * Returns all the children or descendants with the specified name
  387. * and namespace.
  388. *
  389. * @param String $namespace The tag namespace
  390. * @param String $name The tag name
  391. * @param Boolean $recursive Scan the descendants recursively?
  392. * @return Array
  393. */
  394. public function getElementsByTagNameNS($namespace, $name, $recursive = true)
  395. {
  396. if($recursive)
  397. {
  398. return $this->_getElementsByTagName($name, $namespace);
  399. }
  400. if(!is_array($this->_subnodes))
  401. {
  402. return array();
  403. }
  404. $result = array();
  405. foreach($this->_subnodes as $subnode)
  406. {
  407. if(!$subnode instanceof Opt_Xml_Element)
  408. {
  409. continue;
  410. }
  411. if(($subnode->getName() == $name || $name == '*') && ($subnode->getNamespace() == $namespace || $namespace == '*') )
  412. {
  413. $result[] = $subnode;
  414. }
  415. }
  416. return $result;
  417. } // end getElementsByTagNameNS();
  418. /**
  419. * Returns all the descendants with the specified name and namespace.
  420. * Contrary to getElementsByTagNameNS(), the method does not go into
  421. * the matching descendants.
  422. *
  423. * @param String $ns The namespace name
  424. * @param String $name The tag name
  425. * @return Array
  426. */
  427. public function getElementsExt($ns, $name)
  428. {
  429. if(!is_array($this->_subnodes))
  430. {
  431. return array();
  432. }
  433. // Use the queue to avoid recusive calls in this place.
  434. $queue = new SplQueue;
  435. foreach($this->_subnodes as $item)
  436. {
  437. if(is_object($item))
  438. {
  439. $queue->enqueue($item);
  440. }
  441. }
  442. $result = array();
  443. while($queue->count() > 0)
  444. {
  445. $current = $queue->dequeue();
  446. if($current instanceof Opt_Xml_Element)
  447. {
  448. if(is_null($ns))
  449. {
  450. if($current->getName() == $name || $name == '*')
  451. {
  452. $result[] = $current;
  453. continue; // Do not visit the children of the matching node.
  454. }
  455. }
  456. else
  457. {
  458. if(($current->getName() == $name || $name == '*') && ($current->getNamespace() == $ns || $ns == '*') )
  459. {
  460. $result[] = $current;
  461. continue; // Do not visit the children of the matching node.
  462. }
  463. }
  464. }
  465. if($current instanceof Opt_Xml_Scannable)
  466. {
  467. foreach($current as $subnode)
  468. {
  469. $queue->enqueue($subnode);
  470. }
  471. }
  472. }
  473. return $result;
  474. } // end getElementsExt();
  475. /**
  476. * Sorts the children with the order specified in the associative
  477. * array. The array must contain the pairs 'tag name' => order. Moreover,
  478. * it must contain the '*' element representing the new location of
  479. * the rest of the nodes.
  480. *
  481. * @param Array $prototypes The required order.
  482. */
  483. public function sort(Array $prototypes)
  484. {
  485. $this->_prototypes = $prototypes;
  486. if(!isset($prototypes['*']))
  487. {
  488. throw new Opt_APINoWildcard_Exception;
  489. }
  490. // To create a stable sort.
  491. $i = 0;
  492. foreach($this->_subnodes as &$node)
  493. {
  494. if($node instanceof Opt_Xml_Buffer)
  495. {
  496. $node->set('_ssort', $i++);
  497. }
  498. }
  499. // Sort!
  500. usort($this->_subnodes, array($this, 'sortCmp'));
  501. unset($this->_prototypes);
  502. } // end sort();
  503. /**
  504. * Moves the specified node to the end of the children list.
  505. *
  506. * @param Integer|Opt_Xml_Node $node The node to be moved.
  507. * @return Boolean
  508. */
  509. public function bringToEnd($node)
  510. {
  511. if(!is_array($this->_subnodes))
  512. {
  513. return false;
  514. }
  515. if(is_object($node))
  516. {
  517. $i = 0;
  518. $cnt = sizeof($this->_subnodes);
  519. while($cnt > 0)
  520. {
  521. if(isset($this->_subnodes[$i]))
  522. {
  523. // Information: NEVER compare two nodes using "=="!
  524. if($this->_subnodes[$i] === $node)
  525. {
  526. $this->_subnodes[] = $node;
  527. unset($this->_subnodes[$i]);
  528. return true;
  529. }
  530. }
  531. $i++;
  532. }
  533. }
  534. else
  535. {
  536. if(isset($this->_subnodes[$node]))
  537. {
  538. $this->_subnodes[] = $this->_subnodes[$node];
  539. unset($this->_subnodes[$node]);
  540. return true;
  541. }
  542. }
  543. return false;
  544. } // end bringToEnd();
  545. /**
  546. * Returns the internal subnode array.
  547. *
  548. * @internal
  549. * @return Array
  550. */
  551. public function getSubnodeArray()
  552. {
  553. return $this->_subnodes;
  554. } // end getSubnodeArray();
  555. /*
  556. public function clearNode()
  557. {
  558. $queue = new SplQueue;
  559. foreach($this->_subnodes as $subitem)
  560. {
  561. $queue->enqueue($subitem);
  562. }
  563. $this->_subnodes = NULL;
  564. $buffer = array();
  565. while($queue->count() > 0)
  566. {
  567. $item = $queue->dequeue();
  568. foreach($item as $subitem)
  569. {
  570. $queue->enqueue($subitem);
  571. $buffer[] = $subitem;
  572. }
  573. $item->_subnodes = NULL;
  574. }
  575. unset($buffer);
  576. } // end clearNode();
  577. */
  578. protected function _cloneHandler()
  579. {
  580. /* null */
  581. } // end _cloneHandler();
  582. /**
  583. * The cloning helper that clones also all the descendants. The cloning algorithm
  584. * does not use true recursion, so that it can be safely used even with very deep
  585. * trees.
  586. *
  587. * @internal
  588. */
  589. final public function __clone()
  590. {
  591. if($this->get('__nrc') === true)
  592. {
  593. // In this state, we do not clone the subnodes, because some else node takes
  594. // care of it
  595. $this->set('__nrc', NULL);
  596. $this->_subnodes = NULL;
  597. $this->_prototypes = NULL;
  598. $this->_i = NULL;
  599. $this->_size = 0;
  600. $this->_copy = NULL;
  601. $this->_cloneHandler();
  602. }
  603. else
  604. {
  605. if(!is_array($this->_subnodes))
  606. {
  607. $this->_subnodes = NULL;
  608. return;
  609. }
  610. // The main instance of cloning, it makes copies of all the subnodes.
  611. $queue = new SplQueue;
  612. foreach($this->_subnodes as $subitem)
  613. {
  614. if(is_object($subitem))
  615. {
  616. $queue->enqueue(array($subitem, $this));
  617. }
  618. }
  619. $this->_subnodes = NULL;
  620. $this->_prototypes = NULL;
  621. $this->_i = NULL;
  622. $this->_size = 0;
  623. $this->_copy = NULL;
  624. while($queue->count() > 0)
  625. {
  626. $pair = $queue->dequeue();
  627. $pair[0]->set('__nrc', true);
  628. $pair[1]->appendChild($clone = clone $pair[0]);
  629. // Only Opt_Xml_Scannable instances must go deeper.
  630. if($pair[0] instanceof Opt_Xml_Scannable)
  631. {
  632. foreach($pair[0] as $subitem)
  633. {
  634. if(is_object($subitem))
  635. {
  636. $queue->enqueue(array($subitem, $clone));
  637. }
  638. }
  639. }
  640. }
  641. }
  642. } // end __clone();
  643. /**
  644. * Removes the connections between all the descendants so that they can
  645. * be safely collected by the PHP garbage collector. Remember to use this
  646. * method before you free the last reference to the root node.
  647. */
  648. public function dispose()
  649. {
  650. // The main instance of cloning, it makes copies of all the subnodes.
  651. $queue = new SplQueue;
  652. if(is_array($this->_subnodes))
  653. {
  654. foreach($this->_subnodes as $subitem)
  655. {
  656. if(is_object($subitem))
  657. {
  658. $queue->enqueue($subitem);
  659. }
  660. }
  661. }
  662. while($queue->count() > 0)
  663. {
  664. $item = $queue->dequeue();
  665. if($item instanceof Opt_Xml_Scannable)
  666. {
  667. foreach($item as $subitem)
  668. {
  669. if(is_object($subitem))
  670. {
  671. $queue->enqueue($subitem);
  672. }
  673. }
  674. }
  675. $item->_dispose();
  676. }
  677. $this->_dispose();
  678. } // end dispose();
  679. /**
  680. * Extra dispose function.
  681. *
  682. * @internal
  683. */
  684. protected function _dispose()
  685. {
  686. parent::_dispose();
  687. $this->_subnodes = NULL;
  688. $this->_prototypes = NULL;
  689. $this->_i = NULL;
  690. $this->_size = 0;
  691. $this->_copy = NULL;
  692. } // end _dispose();
  693. /*
  694. * Iterator interface implementation
  695. */
  696. public function rewind()
  697. {
  698. if(!is_array($this->_subnodes))
  699. {
  700. $this->_subnodes = array();
  701. }
  702. ksort($this->_subnodes);
  703. $this->_i = 0;
  704. end($this->_subnodes);
  705. $this->_size = key($this->_subnodes);
  706. while(!isset($this->_subnodes[$this->_i]) && $this->_i <= $this->_size)
  707. {
  708. $this->_i++;
  709. }
  710. $this->_copy = $this->_subnodes;
  711. } // end rewind();
  712. public function valid()
  713. {
  714. if($this->_i <= $this->_size)
  715. {
  716. return true;
  717. }
  718. $this->_copy = null;
  719. return false;
  720. } // end valid();
  721. public function current()
  722. {
  723. return $this->_copy[$this->_i];
  724. } // end current();
  725. public function next()
  726. {
  727. do
  728. {
  729. $this->_i++;
  730. }
  731. while(!isset($this->_copy[$this->_i]) && $this->_i <= $this->_size);
  732. } // end next();
  733. public function key()
  734. {
  735. return $this->_i;
  736. } // end key();
  737. /*
  738. * Internal methods
  739. */
  740. final public function sortCmp($node1, $node2)
  741. {
  742. $name1 = (string)$node1;
  743. $name2 = (string)$node2;
  744. if(!isset($this->_prototypes[$name1]))
  745. {
  746. $name1 = '*';
  747. }
  748. if(!isset($this->_prototypes[$name2]))
  749. {
  750. $name2 = '*';
  751. }
  752. if($this->_prototypes[$name1] == $this->_prototypes[$name2])
  753. {
  754. if($node1->get('_ssort') < $node2->get('_ssort'))
  755. {
  756. return -1;
  757. }
  758. return 1;
  759. }
  760. elseif($this->_prototypes[$name1] < $this->_prototypes[$name2])
  761. {
  762. return -1;
  763. }
  764. return +1;
  765. } // end sortCmp();
  766. final protected function _getElementsByTagName($name, $ns)
  767. {
  768. if(!is_array($this->_subnodes))
  769. {
  770. return array();
  771. }
  772. // Use the queue to avoid recusive calls in this place.
  773. $queue = new SplQueue;
  774. foreach($this->_subnodes as $item)
  775. {
  776. if(is_object($item))
  777. {
  778. $queue->enqueue($item);
  779. }
  780. }
  781. $result = array();
  782. while($queue->count() > 0)
  783. {
  784. $current = $queue->dequeue();
  785. if($current instanceof Opt_Xml_Element)
  786. {
  787. if(is_null($ns))
  788. {
  789. if($current->getName() == $name || $name == '*')
  790. {
  791. $result[] = $current;
  792. }
  793. }
  794. else
  795. {
  796. if(($current->getName() == $name || $name == '*') && ($current->getNamespace() == $ns || $ns == '*') )
  797. {
  798. $result[] = $current;
  799. }
  800. }
  801. }
  802. if($current instanceof Opt_Xml_Scannable)
  803. {
  804. foreach($current as $subnode)
  805. {
  806. $queue->enqueue($subnode);
  807. }
  808. }
  809. }
  810. return $result;
  811. } // end _getElementsByTagName();
  812. final protected function _appendChild(Opt_Xml_Node $child, $appendOnError)
  813. {
  814. if($appendOnError)
  815. {
  816. if(!is_array($this->_subnodes))
  817. {
  818. return false;
  819. }
  820. $this->_subnodes[] = $child;
  821. }
  822. else
  823. {
  824. throw new Opt_APIInvalidBorders_Exception;
  825. }
  826. } // end _appendChild();
  827. protected function _testNode(Opt_Xml_Node $node)
  828. {
  829. // This method tests, whether the specified node can be a child
  830. // of the current note. By overwriting this method, we can change
  831. // this behavior.
  832. return true;
  833. } // end _testNode();
  834. private function _arrayReduceHoles($array)
  835. {
  836. $newArray = array();
  837. foreach($array as $value)
  838. {
  839. $newArray[] = $value;
  840. }
  841. return $newArray;
  842. } // end _arrayReduceHoles();
  843. private function _arrayCreateHole($array, $where)
  844. {
  845. $newArray = array();
  846. $i = 0;
  847. foreach($array as $value)
  848. {
  849. if($i == $where)
  850. {
  851. $newArray[$i] = null;
  852. $i++;
  853. }
  854. $newArray[$i] = $value;
  855. $i++;
  856. }
  857. return $newArray;
  858. } // end _arrayCreateHole();
  859. } // end Opt_Xml_Scannable;