PageRenderTime 70ms CodeModel.GetById 6ms RepoModel.GetById 0ms app.codeStats 1ms

/administrator/components/com_virtuemart/classes/shipping/minixml/classes/element.inc.php

https://bitbucket.org/dgough/annamaria-daneswood-25102012
PHP | 1748 lines | 845 code | 395 blank | 508 comment | 163 complexity | 593e948666dcd663db90a80ec3f568c1 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1
  1. <?php
  2. /***************************************************************************************************
  3. ****************************************************************************************************
  4. *****
  5. ***** MiniXML - PHP class library for generating and parsing XML.
  6. *****
  7. ***** Copyright (C) 2002,2003 Patrick Deegan, Psychogenic.com
  8. ***** All rights reserved.
  9. *****
  10. ***** http://minixml.psychogenic.com
  11. *****
  12. ***** This program is free software; you can redistribute
  13. ***** it and/or modify it under the terms of the GNU
  14. ***** General Public License as published by the Free
  15. ***** Software Foundation; either version 2 of the
  16. ***** License, or (at your option) any later version.
  17. *****
  18. ***** This program is distributed in the hope that it will
  19. ***** be useful, but WITHOUT ANY WARRANTY; without even
  20. ***** the implied warranty of MERCHANTABILITY or FITNESS
  21. ***** FOR A PARTICULAR PURPOSE. See the GNU General
  22. ***** Public License for more details.
  23. *****
  24. ***** You should have received a copy of the GNU General
  25. ***** Public License along with this program; if not,
  26. ***** write to the Free Software Foundation, Inc., 675
  27. ***** Mass Ave, Cambridge, MA 02139, USA.
  28. *****
  29. *****
  30. ***** You may contact the author, Pat Deegan, through the
  31. ***** contact section at http://www.psychogenic.com
  32. *****
  33. ***** Much more information on using this API can be found on the
  34. ***** official MiniXML website - http://minixml.psychogenic.com
  35. ***** or within the Perl version (XML::Mini) available through CPAN
  36. *****
  37. ****************************************************************************************************
  38. ***************************************************************************************************/
  39. require_once(MINIXML_CLASSDIR . "/treecomp.inc.php");
  40. require_once(MINIXML_CLASSDIR . "/node.inc.php");
  41. /***************************************************************************************************
  42. ****************************************************************************************************
  43. *****
  44. ***** MiniXMLElement
  45. *****
  46. ****************************************************************************************************
  47. ***************************************************************************************************/
  48. /* class MiniXMLElement (MiniXMLTreeComponent)
  49. **
  50. ** Although the main handle to the xml document is the MiniXMLDoc object,
  51. ** much of the functionality and manipulation involves interaction with
  52. ** MiniXMLElement objects.
  53. **
  54. ** A MiniXMLElement
  55. ** has:
  56. ** - a name
  57. ** - a list of 0 or more attributes (which have a name and a value)
  58. ** - a list of 0 or more children (MiniXMLElement or MiniXMLNode objects)
  59. ** - a parent (optional, only if MINIXML_AUTOSETPARENT > 0)
  60. **/
  61. class MiniXMLElement extends MiniXMLTreeComponent {
  62. var $xname;
  63. var $xattributes;
  64. var $xchildren;
  65. var $xnumChildren;
  66. var $xnumElementChildren;
  67. var $xavoidLoops = MINIXML_AVOIDLOOPS;
  68. /* MiniXMLElement NAME
  69. ** Creates and inits a new MiniXMLElement
  70. */
  71. function MiniXMLElement ($name=NULL)
  72. {
  73. $this->MiniXMLTreeComponent();
  74. $this->xname = NULL;
  75. $this->xattributes = array();
  76. $this->xchildren = array();
  77. $this->xnumChildren = 0;
  78. $this->xnumElementChildren = 0;
  79. if ($name)
  80. {
  81. $this->name($name);
  82. } else {
  83. return _MiniXMLError("MiniXMLElement Constructor: must pass a name to constructor");
  84. }
  85. } /* end method MiniXMLElement */
  86. /**************** Get/set methods for MiniXMLElement data *****************/
  87. /* name [NEWNAME]
  88. **
  89. ** If a NEWNAME string is passed, the MiniXMLElement's name is set
  90. ** to NEWNAME.
  91. **
  92. ** Returns the element's name.
  93. */
  94. function name ($setTo=NULL)
  95. {
  96. if (! is_null($setTo))
  97. {
  98. if (! is_string($setTo))
  99. {
  100. return _MiniXMLError("MiniXMLElement::name() Must pass a STRING to method to set name");
  101. }
  102. $this->xname = $setTo;
  103. }
  104. return $this->xname;
  105. } /* end method name */
  106. /* attribute NAME [SETTO [SETTOALT]]
  107. **
  108. ** The attribute() method is used to get and set the
  109. ** MiniXMLElement's attributes (ie the name/value pairs contained
  110. ** within the tag, <tagname attrib1="value1" attrib2="value2">)
  111. **
  112. ** If SETTO is passed, the attribute's value is set to SETTO.
  113. **
  114. ** If the optional SETTOALT is passed and SETTO is false, the
  115. ** attribute's value is set to SETTOALT. This is usefull in cases
  116. ** when you wish to set the attribute to a default value if no SETTO is
  117. ** present, eg $myelement->attribute('href', $theHref, 'http://psychogenic.com')
  118. ** will default to 'http://psychogenic.com'.
  119. **
  120. ** Note: if the MINIXML_LOWERCASEATTRIBUTES define is > 0, all attribute names
  121. ** will be lowercased (while setting and during retrieval)
  122. **
  123. ** Returns the value associated with attribute NAME.
  124. **
  125. */
  126. function attribute ($name, $primValue=NULL, $altValue=NULL)
  127. {
  128. $value = (is_null($primValue) ? $altValue : $primValue );
  129. if (MINIXML_UPPERCASEATTRIBUTES > 0)
  130. {
  131. $name = strtoupper($name);
  132. } elseif (MINIXML_LOWERCASEATTRIBUTES > 0)
  133. {
  134. $name = strtolower($name);
  135. }
  136. if (! is_null($value))
  137. {
  138. $this->xattributes[$name] = $value;
  139. }
  140. if (isset($this->xattributes[$name]) && ! is_null($this->xattributes[$name]))
  141. {
  142. return $this->xattributes[$name];
  143. } else {
  144. return NULL;
  145. }
  146. } /* end method attribute */
  147. /* text [SETTO [SETTOALT]]
  148. **
  149. ** The text() method is used to get or append text data to this
  150. ** element (it is appended to the child list as a new MiniXMLNode object).
  151. **
  152. ** If SETTO is passed, a new node is created, filled with SETTO
  153. ** and appended to the list of this element's children.
  154. **
  155. ** If the optional SETTOALT is passed and SETTO is false, the
  156. ** new node's value is set to SETTOALT. See the attribute() method
  157. ** for an example use.
  158. **
  159. ** Returns a string composed of all child MiniXMLNodes' contents.
  160. **
  161. ** Note: all the children MiniXMLNodes' contents - including numeric
  162. ** nodes are included in the return string.
  163. */
  164. function text ($setToPrimary = NULL, $setToAlternate=NULL)
  165. {
  166. $setTo = ($setToPrimary ? $setToPrimary : $setToAlternate);
  167. if (! is_null($setTo))
  168. {
  169. $this->createNode($setTo);
  170. }
  171. $retString = '';
  172. /* Extract text from all child nodes */
  173. for($i=0; $i< $this->xnumChildren; $i++)
  174. {
  175. if ($this->isNode($this->xchildren[$i]))
  176. {
  177. $nodeTxt = $this->xchildren[$i]->getValue();
  178. if (! is_null($nodeTxt))
  179. {
  180. $retString .= "$nodeTxt ";
  181. } /* end if text returned */
  182. } /* end if this is a MiniXMLNode */
  183. } /* end loop over all children */
  184. return $retString;
  185. } /* end method text */
  186. /* numeric [SETTO [SETTOALT]]
  187. **
  188. ** The numeric() method is used to get or append numeric data to
  189. ** this element (it is appended to the child list as a MiniXMLNode object).
  190. **
  191. ** If SETTO is passed, a new node is created, filled with SETTO
  192. ** and appended to the list of this element's children.
  193. **
  194. ** If the optional SETTOALT is passed and SETTO is false, the
  195. ** new node's value is set to SETTOALT. See the attribute() method
  196. ** for an example use.
  197. **
  198. ** Returns a space seperated string composed all child MiniXMLNodes'
  199. ** numeric contents.
  200. **
  201. ** Note: ONLY numerical contents are included from the list of child MiniXMLNodes.
  202. **
  203. */
  204. function numeric ($setToPrimary = NULL, $setToAlternate=NULL)
  205. {
  206. $setTo = (is_null($setToPrimary) ? $setToAlternate : $setToPrimary);
  207. if (! is_null($setTo))
  208. {
  209. $this->createNode($setTo);
  210. }
  211. } /* end method numeric */
  212. /* comment CONTENTS
  213. **
  214. ** The comment() method allows you to add a new MiniXMLElementComment to this
  215. ** element's list of children.
  216. **
  217. ** Comments will return a <!-- CONTENTS --> string when the element's toString()
  218. ** method is called.
  219. **
  220. ** Returns a reference to the newly appended MiniXMLElementComment
  221. **
  222. */
  223. function & comment ($contents)
  224. {
  225. $newEl = new MiniXMLElementComment();
  226. $appendedComment =& $this->appendChild($newEl);
  227. $appendedComment->text($contents);
  228. return $appendedComment;
  229. } /* end method comment */
  230. /*
  231. ** docType DEFINITION
  232. **
  233. ** Append a new <!DOCTYPE DEFINITION [ ...]> element as a child of this
  234. ** element.
  235. **
  236. ** Returns the appended DOCTYPE element. You will normally use the returned
  237. ** element to add ENTITY elements, like
  238. ** $newDocType =& $xmlRoot->docType('spec SYSTEM "spec.dtd"');
  239. ** $newDocType->entity('doc.audience', 'public review and discussion');
  240. */
  241. function & docType ($definition)
  242. {
  243. $newElement = new MiniXMLElementDocType($definition);
  244. $appendedElement =& $this->appendChild($newElement);
  245. return $appendedElement;
  246. }
  247. /*
  248. ** entity NAME VALUE
  249. **
  250. ** Append a new <!ENTITY NAME "VALUE"> element as a child of this
  251. ** element.
  252. ** Returns the appended ENTITY element.
  253. */
  254. function & entity ($name,$value)
  255. {
  256. $newElement = new MiniXMLElementEntity($name, $value);
  257. $appendedEl =& $this->appendChild($newElement);
  258. return $appendedEl;
  259. }
  260. /*
  261. ** cdata CONTENTS
  262. **
  263. ** Append a new <![CDATA[ CONTENTS ]]> element as a child of this element.
  264. ** Returns the appended CDATA element.
  265. **
  266. */
  267. function & cdata ($contents)
  268. {
  269. $newElement = new MiniXMLElementCData($contents);
  270. $appendedChild =& $this->appendChild($newElement);
  271. return $appendedChild;
  272. }
  273. /* getValue
  274. **
  275. ** Returns a string containing the value of all the element's
  276. ** child MiniXMLNodes (and all the MiniXMLNodes contained within
  277. ** it's child MiniXMLElements, recursively).
  278. **
  279. ** Note: the seperator parameter remains officially undocumented
  280. ** since I'm not sure it will remain part of the API
  281. */
  282. function getValue ($seperator=' ')
  283. {
  284. $retStr = '';
  285. $valArray = array();
  286. for($i=0; $i < $this->xnumChildren; $i++)
  287. {
  288. $value = $this->xchildren[$i]->getValue();
  289. if (! is_null($value))
  290. {
  291. array_push($valArray, $value);
  292. }
  293. }
  294. if (count($valArray))
  295. {
  296. $retStr = implode($seperator, $valArray);
  297. }
  298. return $retStr;
  299. } /* end method getValue */
  300. /* getElement NAME
  301. ** Searches the element and it's children for an element with name NAME.
  302. **
  303. ** Returns a reference to the first MiniXMLElement with name NAME,
  304. ** if found, NULL otherwise.
  305. **
  306. ** NOTE: The search is performed like this, returning the first
  307. ** element that matches:
  308. **
  309. ** - Check this element for a match
  310. ** - Check this element's immediate children (in order) for a match.
  311. ** - Ask each immediate child (in order) to MiniXMLElement::getElement()
  312. ** (each child will then proceed similarly, checking all it's immediate
  313. ** children in order and then asking them to getElement())
  314. */
  315. function &getElement ($name)
  316. {
  317. if (MINIXML_DEBUG > 0)
  318. {
  319. $elname = $this->name();
  320. _MiniXMLLog("MiniXMLElement::getElement() called for $name on $elname.");
  321. }
  322. if (is_null($name))
  323. {
  324. return _MiniXMLError("MiniXMLElement::getElement() Must Pass Element name.");
  325. }
  326. /** Must only check children as checking $this results in an inability to
  327. *** fetch nested objects with the same name
  328. *** <tag>
  329. *** <nested>
  330. *** <nested>
  331. *** Can't get here from tag or from the first 'nested'
  332. *** </nested>
  333. *** </nested>
  334. *** </tag>
  335. if (MINIXML_CASESENSITIVE > 0)
  336. {
  337. if (strcmp($this->xname, $name) == 0)
  338. {
  339. /* This element is it * /
  340. return $this;
  341. }
  342. } else {
  343. if (strcasecmp($this->xname,$name) == 0)
  344. {
  345. return $this;
  346. }
  347. }
  348. ***** end commented out section ****
  349. */
  350. if (! $this->xnumChildren )
  351. {
  352. /* Not match here and and no kids - not found... */
  353. return NULL;
  354. }
  355. /* Try each child (immediate children take priority) */
  356. for ($i = 0; $i < $this->xnumChildren; $i++)
  357. {
  358. $childname = $this->xchildren[$i]->name();
  359. if ($childname)
  360. {
  361. if (MINIXML_CASESENSITIVE > 0)
  362. {
  363. /* case sensitive matches only */
  364. if (strcmp($name, $childname) == 0)
  365. {
  366. return $this->xchildren[$i];
  367. }
  368. } else {
  369. /* case INsensitive matching */
  370. if (strcasecmp($name, $childname) == 0)
  371. {
  372. return $this->xchildren[$i];
  373. }
  374. } /* end if case sensitive */
  375. } /* end if child has a name */
  376. } /* end loop over all my children */
  377. /* Use beautiful recursion, daniel san */
  378. for ($i = 0; $i < $this->xnumChildren; $i++)
  379. {
  380. $theelement = $this->xchildren[$i]->getElement($name);
  381. if ($theelement)
  382. {
  383. if (MINIXML_DEBUG > 0)
  384. {
  385. _MiniXMLLog("MiniXMLElement::getElement() returning element $theelement");
  386. }
  387. return $theelement;
  388. }
  389. }
  390. /* Not found */
  391. return NULL;
  392. } /* end method getElement */
  393. /* getElementByPath PATH
  394. ** Attempts to return a reference to the (first) element at PATH
  395. ** where PATH is the path in the structure (relative to this element) to
  396. ** the requested element.
  397. **
  398. ** For example, in the document represented by:
  399. **
  400. ** <partRateRequest>
  401. ** <vendor>
  402. ** <accessid user="myusername" password="mypassword" />
  403. ** </vendor>
  404. ** <partList>
  405. ** <partNum>
  406. ** DA42
  407. ** </partNum>
  408. ** <partNum>
  409. ** D99983FFF
  410. ** </partNum>
  411. ** <partNum>
  412. ** ss-839uent
  413. ** </partNum>
  414. ** </partList>
  415. ** </partRateRequest>
  416. **
  417. ** $partRate =& $xmlDocument->getElement('partRateRequest');
  418. **
  419. ** $accessid =& $partRate->getElementByPath('vendor/accessid');
  420. **
  421. ** Will return what you expect (the accessid element with attributes user = "myusername"
  422. ** and password = "mypassword").
  423. **
  424. ** BUT be careful:
  425. ** $accessid =& $partRate->getElementByPath('partList/partNum');
  426. **
  427. ** will return the partNum element with the value "DA42". Other partNums are
  428. ** inaccessible by getElementByPath() - Use MiniXMLElement::getAllChildren() instead.
  429. **
  430. ** Returns the MiniXMLElement reference if found, NULL otherwise.
  431. */
  432. function &getElementByPath($path)
  433. {
  434. $names = split ("/", $path);
  435. $element = $this;
  436. foreach ($names as $elementName)
  437. {
  438. if ($element && $elementName) /* Make sure we didn't hit a dead end and that we have a name*/
  439. {
  440. /* Ask this element to get the next child in path */
  441. $element = $element->getElement($elementName);
  442. }
  443. }
  444. return $element;
  445. } /* end method getElementByPath */
  446. /* numChildren [NAMED]
  447. **
  448. ** Returns the number of immediate children for this element
  449. **
  450. ** If the optional NAMED parameter is passed, returns only the
  451. ** number of immediate children named NAMED.
  452. */
  453. function numChildren ($named=NULL)
  454. {
  455. if (is_null($named))
  456. {
  457. return $this->xnumElementChildren;
  458. }
  459. /* We require only children named '$named' */
  460. $allkids =& $this->getAllChildren($named);
  461. return count($allkids);
  462. }
  463. /* getAllChildren [NAME]
  464. **
  465. ** Returns a reference to an array of all this element's MiniXMLElement children
  466. **
  467. ** Note: although the MiniXMLElement may contain MiniXMLNodes as children, these are
  468. ** not part of the returned list.
  469. **/
  470. function &getAllChildren ($name=NULL)
  471. {
  472. $retArray = array();
  473. $count = 0;
  474. if (is_null($name))
  475. {
  476. /* Return all element children */
  477. for($i=0; $i < $this->xnumChildren; $i++)
  478. {
  479. if (method_exists($this->xchildren[$i], 'MiniXMLElement'))
  480. {
  481. $retArray[$count++] = $this->xchildren[$i];
  482. }
  483. }
  484. } else {
  485. /* Return only element children with name $name */
  486. for($i=0; $i < $this->xnumChildren; $i++)
  487. {
  488. if (method_exists($this->xchildren[$i], 'MiniXMLElement'))
  489. {
  490. if (MINIXML_CASESENSITIVE > 0)
  491. {
  492. if ($this->xchildren[$i]->name() == $name)
  493. {
  494. $retArray[$count++] = $this->xchildren[$i];
  495. }
  496. } else {
  497. if (strcasecmp($this->xchildren[$i]->name(), $name) == 0)
  498. {
  499. $retArray[$count++] = $this->xchildren[$i];
  500. }
  501. } /* end if case sensitive */
  502. } /* end if child is a MiniXMLElement object */
  503. } /* end loop over all children */
  504. } /* end if specific name was requested */
  505. return $retArray;
  506. } /* end method getAllChildren */
  507. function &insertChild (&$child, $idx=0)
  508. {
  509. if (! $this->_validateChild($child))
  510. {
  511. return;
  512. }
  513. /* Set the parent for the child element to this element if
  514. ** avoidLoops or MINIXML_AUTOSETPARENT is set
  515. */
  516. if ($this->xavoidLoops || (MINIXML_AUTOSETPARENT > 0) )
  517. {
  518. if ($this->xparent == $child)
  519. {
  520. $cname = $child->name();
  521. return _MiniXMLError("MiniXMLElement::insertChild() Tryng to append parent $cname as child of "
  522. . $this->xname );
  523. }
  524. $child->parent($this);
  525. }
  526. $nextIdx = $this->xnumChildren;
  527. $lastIdx = $nextIdx - 1;
  528. if ($idx > $lastIdx)
  529. {
  530. if ($idx > $nextIdx)
  531. {
  532. $idx = $lastIdx + 1;
  533. }
  534. $this->xchildren[$idx] = $child;
  535. $this->xnumChildren++;
  536. if ($this->isElement($child))
  537. {
  538. $this->xnumElementChildren++;
  539. }
  540. } elseif ($idx >= 0)
  541. {
  542. $removed = array_splice($this->xchildren, $idx);
  543. array_push($this->xchildren, $child);
  544. $numRemoved = count($removed);
  545. for($i=0; $i<$numRemoved; $i++)
  546. {
  547. array_push($this->xchildren, $removed[$i]);
  548. }
  549. $this->xnumChildren++;
  550. if ($this->isElement($child))
  551. {
  552. $this->xnumElementChildren++;
  553. }
  554. } else {
  555. $revIdx = (-1 * $idx) % $this->xnumChildren;
  556. $newIdx = $this->xnumChildren - $revIdx;
  557. if ($newIdx < 0)
  558. {
  559. return _MiniXMLError("Element::insertChild() Ended up with a negative index? ($newIdx)");
  560. }
  561. return $this->insertChild($child, $newIdx);
  562. }
  563. return $child;
  564. }
  565. /* appendChild CHILDELEMENT
  566. **
  567. ** appendChild is used to append an existing MiniXMLElement object to
  568. ** this element's list.
  569. **
  570. ** Returns a reference to the appended child element.
  571. **
  572. ** NOTE: Be careful not to create loops in the hierarchy, eg
  573. ** $parent->appendChild($child);
  574. ** $child->appendChild($subChild);
  575. ** $subChild->appendChild($parent);
  576. **
  577. ** If you want to be sure to avoid loops, set the MINIXML_AVOIDLOOPS define
  578. ** to 1 or use the avoidLoops() method (will apply to all children added with createChild())
  579. */
  580. function &appendChild (&$child)
  581. {
  582. if (! $this->_validateChild($child))
  583. {
  584. return;
  585. }
  586. /* Set the parent for the child element to this element if
  587. ** avoidLoops or MINIXML_AUTOSETPARENT is set
  588. */
  589. if ($this->xavoidLoops || (MINIXML_AUTOSETPARENT > 0) )
  590. {
  591. if ($this->xparent == $child)
  592. {
  593. $cname = $child->name();
  594. return _MiniXMLError("MiniXMLElement::appendChild() Tryng to append parent $cname as child of "
  595. . $this->xname );
  596. }
  597. $child->parent($this);
  598. }
  599. $this->xnumElementChildren++; /* Note that we're addind a MiniXMLElement child */
  600. /* Add the child to the list */
  601. $idx = $this->xnumChildren++;
  602. $this->xchildren[$idx] =& $child;
  603. return $this->xchildren[$idx];
  604. } /* end method appendChild */
  605. /* prependChild CHILDELEMENT
  606. **
  607. ** prependChild is used to prepend an existing MiniXMLElement object to
  608. ** this element's list. The child will be positioned at the begining of
  609. ** the elements child list, thus it will be output first in the resulting XML.
  610. **
  611. ** Returns a reference to the prepended child element.
  612. */
  613. function &prependChild ($child)
  614. {
  615. $this->_validateChild($child);
  616. /* Set the parent for the child element to this element if
  617. ** avoidLoops or MINIXML_AUTOSETPARENT is set
  618. */
  619. if ($this->xavoidLoops || (MINIXML_AUTOSETPARENT > 0) )
  620. {
  621. if ($this->xparent == $child)
  622. {
  623. $cname = $child->name();
  624. return _MiniXMLError("MiniXMLElement::appendChild() Tryng to append parent $cname as child of "
  625. . $this->xname );
  626. }
  627. $child->parent($this);
  628. }
  629. $this->xnumElementChildren++; /* Note that we're adding a MiniXMLElement child */
  630. /* Add the child to the list */
  631. $idx = $this->xnumChildren++;
  632. array_unshift($this->xchildren, $child);
  633. return $this->xchildren[0];
  634. } /* end method prependChild */
  635. function _validateChild (&$child)
  636. {
  637. if (is_null($child))
  638. {
  639. return _MiniXMLError("MiniXMLElement::_validateChild() need to pass a non-NULL MiniXMLElement child.");
  640. }
  641. if (! method_exists($child, 'MiniXMLElement'))
  642. {
  643. return _MiniXMLError("MiniXMLElement::_validateChild() must pass a MiniXMLElement object to _validateChild.");
  644. }
  645. /* Make sure element is named */
  646. $cname = $child->name();
  647. if (is_null($cname))
  648. {
  649. return _MiniXMLError("MiniXMLElement::_validateChild() children must be named");
  650. }
  651. /* Check for loops */
  652. if ($child == $this)
  653. {
  654. return _MiniXMLError("MiniXMLElement::_validateChild() Trying to append self as own child!");
  655. } elseif ( $this->xavoidLoops && $child->parent())
  656. {
  657. return _MiniXMLError("MiniXMLElement::_validateChild() Trying to append a child ($cname) that already has a parent set "
  658. . "while avoidLoops is on - aborting");
  659. }
  660. return 1;
  661. }
  662. /* createChild ELEMENTNAME [VALUE]
  663. **
  664. ** Creates a new MiniXMLElement instance and appends it to the list
  665. ** of this element's children.
  666. ** The new child element's name is set to ELEMENTNAME.
  667. **
  668. ** If the optional VALUE (string or numeric) parameter is passed,
  669. ** the new element's text/numeric content will be set using VALUE.
  670. **
  671. ** Returns a reference to the new child element
  672. **
  673. ** Note: don't forget to use the =& (reference assignment) operator
  674. ** when calling createChild:
  675. **
  676. ** $newChild =& $myElement->createChild('newChildName');
  677. **
  678. */
  679. function & createChild ($name, $value=NULL)
  680. {
  681. if (! $name)
  682. {
  683. return _MiniXMLError("MiniXMLElement::createChild() Must pass a NAME to createChild.");
  684. }
  685. if (! is_string($name))
  686. {
  687. return _MiniXMLError("MiniXMLElement::createChild() Name of child must be a STRING");
  688. }
  689. $child =& new MiniXMLElement($name);
  690. $appendedChild =& $this->appendChild($child);
  691. if (! is_null($value))
  692. {
  693. if (is_numeric($value))
  694. {
  695. $appendedChild->numeric($value);
  696. } elseif (is_string($value))
  697. {
  698. $appendedChild->text($value);
  699. }
  700. }
  701. $appendedChild->avoidLoops($this->xavoidLoops);
  702. return $appendedChild;
  703. } /* end method createChild */
  704. /* removeChild CHILD
  705. ** Removes CHILD from this element's list of children.
  706. **
  707. ** Returns the removed child, if found, NULL otherwise.
  708. */
  709. function &removeChild (&$child)
  710. {
  711. if (! $this->xnumChildren)
  712. {
  713. if (MINIXML_DEBUG > 0)
  714. {
  715. _MiniXMLLog("Element::removeChild() called for element without any children.") ;
  716. }
  717. return NULL;
  718. }
  719. $foundChild;
  720. $idx = 0;
  721. while ($idx < $this->xnumChildren && ! $foundChild)
  722. {
  723. if ($this->xchildren[$idx] == $child)
  724. {
  725. $foundChild =& $this->xchildren[$idx];
  726. } else {
  727. $idx++;
  728. }
  729. }
  730. if (! $foundChild)
  731. {
  732. if (MINIXML_DEBUG > 0)
  733. {
  734. _MiniXMLLog("Element::removeChild() No matching child found.") ;
  735. }
  736. return NULL;
  737. }
  738. array_splice($this->xchildren, $idx, 1);
  739. $this->xnumChildren--;
  740. if ($this->isElement($foundChild))
  741. {
  742. $this->xnumElementChildren--;
  743. }
  744. unset ($foundChild->xparent) ;
  745. return $foundChild;
  746. }
  747. /* removeAllChildren
  748. ** Removes all children of this element.
  749. **
  750. ** Returns an array of the removed children (which may be empty)
  751. */
  752. function &removeAllChildren ()
  753. {
  754. $emptyArray = array();
  755. if (! $this->xnumChildren)
  756. {
  757. return $emptyArray;
  758. }
  759. $retList =& $this->xchildren;
  760. $idx = 0;
  761. while ($idx < $this->xnumChildren)
  762. {
  763. unset ($retList[$idx++]->xparent);
  764. }
  765. $this->xchildren = array();
  766. $this->xnumElementChildren = 0;
  767. $this->xnumChildren = 0;
  768. return $retList;
  769. }
  770. function & remove ()
  771. {
  772. $parent =& $this->parent();
  773. if (!$parent)
  774. {
  775. _MiniXMLLog("XML::Mini::Element::remove() called for element with no parent set. Aborting.");
  776. return NULL;
  777. }
  778. $removed =& $parent->removeChild($this);
  779. return $removed;
  780. }
  781. /* parent NEWPARENT
  782. **
  783. ** The parent() method is used to get/set the element's parent.
  784. **
  785. ** If the NEWPARENT parameter is passed, sets the parent to NEWPARENT
  786. ** (NEWPARENT must be an instance of MiniXMLElement)
  787. **
  788. ** Returns a reference to the parent MiniXMLElement if set, NULL otherwise.
  789. **
  790. ** Note: This method is mainly used internally and you wouldn't normally need
  791. ** to use it.
  792. ** It get's called on element appends when MINIXML_AUTOSETPARENT or
  793. ** MINIXML_AVOIDLOOPS or avoidLoops() > 1
  794. **
  795. */
  796. function &parent (&$setParent)
  797. {
  798. if (! is_null($setParent))
  799. {
  800. /* Parents can only be MiniXMLElement objects */
  801. if (! $this->isElement($setParent))
  802. {
  803. return _MiniXMLError("MiniXMLElement::parent(): Must pass an instance of MiniXMLElement to set.");
  804. }
  805. $this->xparent = $setParent;
  806. }
  807. return $this->xparent;
  808. } /* end method parent */
  809. /* avoidLoops SETTO
  810. **
  811. ** The avoidLoops() method is used to get or set the avoidLoops flag for this element.
  812. **
  813. ** When avoidLoops is true, children with parents already set can NOT be appended to any
  814. ** other elements. This is overkill but it is a quick and easy way to avoid infinite loops
  815. ** in the heirarchy.
  816. **
  817. ** The avoidLoops default behavior is configured with the MINIXML_AVOIDLOOPS define but can be
  818. ** set on individual elements (and automagically all the element's children) with the
  819. ** avoidLoops() method.
  820. **
  821. ** Returns the current value of the avoidLoops flag for the element.
  822. **
  823. */
  824. function avoidLoops ($setTo = NULL)
  825. {
  826. if (! is_null($setTo))
  827. {
  828. $this->xavoidLoops = $setTo;
  829. }
  830. return $this->xavoidLoops;
  831. }
  832. /* toString [SPACEOFFSET]
  833. **
  834. ** toString returns an XML string based on the element's attributes,
  835. ** and content (recursively doing the same for all children)
  836. **
  837. ** The optional SPACEOFFSET parameter sets the number of spaces to use
  838. ** after newlines for elements at this level (adding 1 space per level in
  839. ** depth). SPACEOFFSET defaults to 0.
  840. **
  841. ** If SPACEOFFSET is passed as MINIXML_NOWHITESPACES.
  842. ** no \n or whitespaces will be inserted in the xml string
  843. ** (ie it will all be on a single line with no spaces between the tags.
  844. **
  845. ** Returns the XML string.
  846. **
  847. **
  848. ** Note: Since the toString() method recurses into child elements and because
  849. ** of the MINIXML_NOWHITESPACES and our desire to avoid testing for this value
  850. ** on every element (as it does not change), here we split up the toString method
  851. ** into 2 subs: toStringWithWhiteSpaces(DEPTH) and toStringNoWhiteSpaces().
  852. **
  853. ** Each of these methods, which are to be considered private (?), in turn recurses
  854. ** calling the appropriate With/No WhiteSpaces toString on it's children - thereby
  855. ** avoiding the test on SPACEOFFSET
  856. */
  857. function toString ($depth=0)
  858. {
  859. if ($depth == MINIXML_NOWHITESPACES)
  860. {
  861. return $this->toStringNoWhiteSpaces();
  862. } else {
  863. return $this->toStringWithWhiteSpaces($depth);
  864. }
  865. }
  866. function toStringWithWhiteSpaces ($depth=0)
  867. {
  868. $attribString = '';
  869. $elementName = $this->xname;
  870. $spaces = $this->_spaceStr($depth) ;
  871. $retString = "$spaces<$elementName";
  872. foreach ($this->xattributes as $attrname => $attrvalue)
  873. {
  874. $attribString .= "$attrname=\"$attrvalue\" ";
  875. }
  876. if ($attribString)
  877. {
  878. $attribString = rtrim($attribString);
  879. $retString .= " $attribString";
  880. }
  881. if (! $this->xnumChildren)
  882. {
  883. /* No kids -> no sub-elements, no text, nothing - consider a <unary/> element */
  884. $retString .= " />\n";
  885. return $retString;
  886. }
  887. /* If we've gotten this far, the element has
  888. ** kids or text - consider a <binary>otherstuff</binary> element
  889. */
  890. $onlyTxtChild = 0;
  891. if ($this->xnumChildren == 1 && ! $this->xnumElementChildren)
  892. {
  893. $onlyTxtChild = 1;
  894. }
  895. if ($onlyTxtChild)
  896. {
  897. $nextDepth = 0;
  898. $retString .= "> ";
  899. } else {
  900. $nextDepth = $depth+1;
  901. $retString .= ">\n";
  902. }
  903. for ($i=0; $i < $this->xnumChildren ; $i++)
  904. {
  905. if (method_exists($this->xchildren[$i], 'toStringWithWhiteSpaces') )
  906. {
  907. $newStr = $this->xchildren[$i]->toStringWithWhiteSpaces($nextDepth);
  908. if (! is_null($newStr))
  909. {
  910. if (! ( preg_match("/\n\$/", $newStr) || $onlyTxtChild) )
  911. {
  912. $newStr .= "\n";
  913. }
  914. $retString .= $newStr;
  915. }
  916. } else {
  917. _MiniXMLLog("Invalid child found in $elementName ". $this->xchildren[$i]->name() );
  918. } /* end if has a toString method */
  919. } /* end loop over all children */
  920. /* add the indented closing tag */
  921. if ($onlyTxtChild)
  922. {
  923. $retString .= " </$elementName>\n";
  924. } else {
  925. $retString .= "$spaces</$elementName>\n";
  926. }
  927. return $retString;
  928. } /* end method toString */
  929. function toStringNoWhiteSpaces ()
  930. {
  931. $retString = '';
  932. $attribString = '';
  933. $elementName = $this->xname;
  934. foreach ($this->xattributes as $attrname => $attrvalue)
  935. {
  936. $attribString .= "$attrname=\"$attrvalue\" ";
  937. }
  938. $retString = "<$elementName";
  939. if ($attribString)
  940. {
  941. $attribString = rtrim($attribString);
  942. $retString .= " $attribString";
  943. }
  944. if (! $this->xnumChildren)
  945. {
  946. /* No kids -> no sub-elements, no text, nothing - consider a <unary/> element */
  947. $retString .= " />";
  948. return $retString;
  949. }
  950. /* If we've gotten this far, the element has
  951. ** kids or text - consider a <binary>otherstuff</binary> element
  952. */
  953. $retString .= ">";
  954. /* Loop over all kids, getting associated strings */
  955. for ($i=0; $i < $this->xnumChildren ; $i++)
  956. {
  957. if (method_exists($this->xchildren[$i], 'toStringNoWhiteSpaces') )
  958. {
  959. $newStr = $this->xchildren[$i]->toStringNoWhiteSpaces();
  960. if (! is_null($newStr))
  961. {
  962. $retString .= $newStr;
  963. }
  964. } else {
  965. _MiniXMLLog("Invalid child found in $elementName");
  966. } /* end if has a toString method */
  967. } /* end loop over all children */
  968. /* add the indented closing tag */
  969. $retString .= "</$elementName>";
  970. return $retString;
  971. } /* end method toStringNoWhiteSpaces */
  972. /* toStructure
  973. **
  974. ** Converts an element to a structure - either an array or a simple string.
  975. **
  976. ** This method is used by MiniXML documents to perform their toArray() magic.
  977. */
  978. function toStructure ()
  979. {
  980. $retHash = array();
  981. $contents = "";
  982. $numAdded = 0;
  983. foreach ($this->xattributes as $attrname => $attrvalue)
  984. {
  985. $retHash[$attrname] = $attrvalue;
  986. $numAdded++;
  987. }
  988. for($i=0; $i< $this->xnumChildren; $i++)
  989. {
  990. if ($this->isElement($this->xchildren[$i]))
  991. {
  992. $name = $this->xchildren[$i]->name();
  993. $struct = $this->xchildren[$i]->toStructure();
  994. $existing = NULL;
  995. if (isset($retHash[$name]))
  996. {
  997. $existing =& $retHash[$name];
  998. }
  999. if ($existing)
  1000. {
  1001. if (_MiniXML_NumKeyArray($existing))
  1002. {
  1003. array_push($existing, $struct);
  1004. } else {
  1005. $newArray = array();
  1006. array_push($newArray, $existing);
  1007. array_push($newArray, $struct);
  1008. $retHash[$name] =& $newArray;
  1009. }
  1010. } else {
  1011. $retHash[$name] = $struct;
  1012. }
  1013. $numAdded++;
  1014. } else {
  1015. $contents .= $this->xchildren[$i]->getValue();
  1016. }
  1017. }
  1018. if ($numAdded)
  1019. {
  1020. if (! empty($contents))
  1021. {
  1022. $retHash['-content'] = $contents;
  1023. }
  1024. return $retHash;
  1025. } else {
  1026. return $contents;
  1027. }
  1028. } // end toStructure() method
  1029. /* isElement ELEMENT
  1030. ** Returns a true value if ELEMENT is an instance of MiniXMLElement,
  1031. ** false otherwise.
  1032. **
  1033. ** Note: Used internally.
  1034. */
  1035. function isElement (&$testme)
  1036. {
  1037. if (is_null($testme))
  1038. {
  1039. return 0;
  1040. }
  1041. return method_exists($testme, 'MiniXMLElement');
  1042. }
  1043. /* isNode NODE
  1044. ** Returns a true value if NODE is an instance of MiniXMLNode,
  1045. ** false otherwise.
  1046. **
  1047. ** Note: used internally.
  1048. */
  1049. function isNode (&$testme)
  1050. {
  1051. if (is_null($testme))
  1052. {
  1053. return 0;
  1054. }
  1055. return method_exists($testme, 'MiniXMLNode');
  1056. }
  1057. /* createNode NODEVALUE [ESCAPEENTITIES]
  1058. **
  1059. ** Private (?)
  1060. **
  1061. ** Creates a new MiniXMLNode instance and appends it to the list
  1062. ** of this element's children.
  1063. ** The new child node's value is set to NODEVALUE.
  1064. **
  1065. ** Returns a reference to the new child node.
  1066. **
  1067. ** Note: You don't need to use this method normally - it is used
  1068. ** internally when appending text() and such data.
  1069. **
  1070. */
  1071. function & createNode (&$value, $escapeEntities=NULL)
  1072. {
  1073. $newNode = new MiniXMLNode($value, $escapeEntities);
  1074. $appendedNode =& $this->appendNode($newNode);
  1075. return $appendedNode;
  1076. }
  1077. /* appendNode CHILDNODE
  1078. **
  1079. ** appendNode is used to append an existing MiniXMLNode object to
  1080. ** this element's list.
  1081. **
  1082. ** Returns a reference to the appended child node.
  1083. **
  1084. **
  1085. ** Note: You don't need to use this method normally - it is used
  1086. ** internally when appending text() and such data.
  1087. */
  1088. function &appendNode (&$node)
  1089. {
  1090. if (is_null($node))
  1091. {
  1092. return _MiniXMLError("MiniXMLElement::appendNode() need to pass a non-NULL MiniXMLNode.");
  1093. }
  1094. if (! method_exists($node, 'MiniXMLNode'))
  1095. {
  1096. return _MiniXMLError("MiniXMLElement::appendNode() must pass a MiniXMLNode object to appendNode.");
  1097. }
  1098. if (MINIXML_AUTOSETPARENT)
  1099. {
  1100. if ($this->xparent == $node)
  1101. {
  1102. return _MiniXMLError("MiniXMLElement::appendnode() Tryng to append parent $cname as node of "
  1103. . $this->xname );
  1104. }
  1105. $node->parent($this);
  1106. }
  1107. $idx = $this->xnumChildren++;
  1108. $this->xchildren[$idx] = $node;
  1109. return $this->xchildren[$idx];
  1110. }
  1111. } /* end MiniXMLElement class definition */
  1112. /***************************************************************************************************
  1113. ****************************************************************************************************
  1114. *****
  1115. ***** MiniXMLElementComment
  1116. *****
  1117. ****************************************************************************************************
  1118. ***************************************************************************************************/
  1119. /* The MiniXMLElementComment class is a specific extension of the MiniXMLElement class.
  1120. **
  1121. ** It is used to create the special <!-- comment --> tags and an instance in created when calling
  1122. ** $elementObject->comment('this is a comment');
  1123. **
  1124. ** It's methods are the same as for MiniXMLElement - see those for documentation.
  1125. **/
  1126. class MiniXMLElementComment extends MiniXMLElement {
  1127. function MiniXMLElementComment ($name=NULL)
  1128. {
  1129. $this->MiniXMLElement('!--');
  1130. }
  1131. function toString ($depth=0)
  1132. {
  1133. if ($depth == MINIXML_NOWHITESPACES)
  1134. {
  1135. return $this->toStringNoWhiteSpaces();
  1136. } else {
  1137. return $this->toStringWithWhiteSpaces($depth);
  1138. }
  1139. }
  1140. function toStringWithWhiteSpaces ($depth=0)
  1141. {
  1142. $spaces = $this->_spaceStr($depth) ;
  1143. $retString = "$spaces<!-- \n";
  1144. if (! $this->xnumChildren)
  1145. {
  1146. /* No kids, no text - consider a <unary/> element */
  1147. $retString .= " -->\n";
  1148. return $retString;
  1149. }
  1150. /* If we get here, the element does have children... get their contents */
  1151. $nextDepth = $depth+1;
  1152. for ($i=0; $i < $this->xnumChildren ; $i++)
  1153. {
  1154. $retString .= $this->xchildren[$i]->toStringWithWhiteSpaces($nextDepth);
  1155. }
  1156. $retString .= "\n$spaces -->\n";
  1157. return $retString;
  1158. }
  1159. function toStringNoWhiteSpaces ()
  1160. {
  1161. $retString = '';
  1162. $retString = "<!-- ";
  1163. if (! $this->xnumChildren)
  1164. {
  1165. /* No kids, no text - consider a <unary/> element */
  1166. $retString .= " -->";
  1167. return $retString;
  1168. }
  1169. /* If we get here, the element does have children... get their contents */
  1170. for ($i=0; $i < $this->xnumChildren ; $i++)
  1171. {
  1172. $retString .= $this->xchildren[$i]->toStringNoWhiteSpaces();
  1173. }
  1174. $retString .= " -->";
  1175. return $retString;
  1176. }
  1177. }
  1178. /***************************************************************************************************
  1179. ****************************************************************************************************
  1180. *****
  1181. ***** MiniXMLElementCData
  1182. *****
  1183. ****************************************************************************************************
  1184. ***************************************************************************************************/
  1185. /* The MiniXMLElementCData class is a specific extension of the MiniXMLElement class.
  1186. **
  1187. ** It is used to create the special <![CDATA [ data ]]> tags and an instance in created when calling
  1188. ** $elementObject->cdata('data');
  1189. **
  1190. ** It's methods are the same as for MiniXMLElement - see those for documentation.
  1191. **/
  1192. class MiniXMLElementCData extends MiniXMLElement {
  1193. function MiniXMLElementCData ($contents)
  1194. {
  1195. $this->MiniXMLElement('CDATA');
  1196. if (! is_null($contents))
  1197. {
  1198. $this->createNode($contents, 0) ;
  1199. }
  1200. }
  1201. function toStringNoWhiteSpaces ()
  1202. {
  1203. return $this->toString(MINIXML_NOWHITESPACES);
  1204. }
  1205. function toStringWithWhiteSpaces ($depth=0)
  1206. {
  1207. return $this->toString($depth);
  1208. }
  1209. function toString ($depth=0)
  1210. {
  1211. $spaces = '';
  1212. if ($depth != MINIXML_NOWHITESPACES)
  1213. {
  1214. $spaces = $this->_spaceStr($depth);
  1215. }
  1216. $retString = "$spaces<![CDATA[ ";
  1217. if (! $this->xnumChildren)
  1218. {
  1219. $retString .= "]]>\n";
  1220. return $retString;
  1221. }
  1222. for ( $i=0; $i < $this->xnumChildren; $i++)
  1223. {
  1224. $retString .= $this->xchildren[$i]->getValue();
  1225. }
  1226. $retString .= " ]]>\n";
  1227. return $retString;
  1228. }
  1229. }
  1230. /***************************************************************************************************
  1231. ****************************************************************************************************
  1232. *****
  1233. ***** MiniXMLElementDocType
  1234. *****
  1235. ****************************************************************************************************
  1236. ***************************************************************************************************/
  1237. /* The MiniXMLElementDocType class is a specific extension of the MiniXMLElement class.
  1238. **
  1239. ** It is used to create the special <!DOCTYPE def [...]> tags and an instance in created when calling
  1240. ** $elementObject->comment('');
  1241. **
  1242. ** It's methods are the same as for MiniXMLElement - see those for documentation.
  1243. **/
  1244. class MiniXMLElementDocType extends MiniXMLElement {
  1245. var $dtattr;
  1246. function MiniXMLElementDocType ($attr)
  1247. {
  1248. $this->MiniXMLElement('DOCTYPE');
  1249. $this->dtattr = $attr;
  1250. }
  1251. function toString ($depth)
  1252. {
  1253. if ($depth == MINIXML_NOWHITESPACES)
  1254. {
  1255. return $this->toStringNoWhiteSpaces();
  1256. } else {
  1257. return $this->toStringWithWhiteSpaces($depth);
  1258. }
  1259. }
  1260. function toStringWithWhiteSpaces ($depth=0)
  1261. {
  1262. $spaces = $this->_spaceStr($depth);
  1263. $retString = "$spaces<!DOCTYPE " . $this->dtattr . " [\n";
  1264. if (! $this->xnumChildren)
  1265. {
  1266. $retString .= "]>\n";
  1267. return $retString;
  1268. }
  1269. $nextDepth = $depth + 1;
  1270. for ( $i=0; $i < $this->xnumChildren; $i++)
  1271. {
  1272. $retString .= $this->xchildren[$i]->toStringWithWhiteSpaces($nextDepth);
  1273. }
  1274. $retString .= "\n$spaces]>\n";
  1275. return $retString;
  1276. }
  1277. function toStringNoWhiteSpaces ()
  1278. {
  1279. $retString = "<!DOCTYPE " . $this->dtattr . " [ ";
  1280. if (! $this->xnumChildren)
  1281. {
  1282. $retString .= "]>\n";
  1283. return $retString;
  1284. }
  1285. for ( $i=0; $i < $this->xnumChildren; $i++)
  1286. {
  1287. $retString .= $this->xchildren[$i]->toStringNoWhiteSpaces();
  1288. }
  1289. $retString .= " ]>\n";
  1290. return $retString;
  1291. }
  1292. }
  1293. /***************************************************************************************************
  1294. ****************************************************************************************************
  1295. *****
  1296. ***** MiniXMLElementEntity
  1297. *****
  1298. ****************************************************************************************************
  1299. ***************************************************************************************************/
  1300. /* The MiniXMLElementEntity class is a specific extension of the MiniXMLElement class.
  1301. **
  1302. ** It is used to create the special <!ENTITY name "val"> tags and an instance in created when calling
  1303. ** $elementObject->comment('');
  1304. **
  1305. ** It's methods are the same as for MiniXMLElement - see those for documentation.
  1306. **/
  1307. class MiniXMLElementEntity extends MiniXMLElement {
  1308. function MiniXMLElementEntity ($name, $value=NULL)
  1309. {
  1310. $this->MiniXMLElement($name);
  1311. if (! is_null ($value))
  1312. {
  1313. $this->createNode($value, 0);
  1314. }
  1315. }
  1316. function toString ($depth = 0)
  1317. {
  1318. $spaces = '';
  1319. if ($depth != MINIXML_NOWHITESPACES)
  1320. {
  1321. $spaces = $this->_spaceStr($depth);
  1322. }
  1323. $retString = "$spaces<!ENTITY " . $this->name();
  1324. if (! $this->xnumChildren)
  1325. {
  1326. $retString .= ">\n";
  1327. return $retString;
  1328. }
  1329. $nextDepth = ($depth == MINIXML_NOWHITESPACES) ? MINIXML_NOWHITESPACES
  1330. : $depth + 1;
  1331. $retString .= '"';
  1332. for ( $i=0; $i < $this->xnumChildren; $i++)
  1333. {
  1334. $retString .= $this->xchildren[$i]->toString(MINIXML_NOWHITESPACES);
  1335. }
  1336. $retString .= '"';
  1337. $retString .= " >\n";
  1338. return $retString;
  1339. }
  1340. function toStringNoWhiteSpaces ()
  1341. {
  1342. return $this->toString(MINIXML_NOWHITESPACES);
  1343. }
  1344. function toStringWithWhiteSpaces ($depth=0)
  1345. {
  1346. return $this->toString($depth);
  1347. }
  1348. }
  1349. ?>