A modest collection of PHP libraries used at SparkFun.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

197 lines
4.9 KiB

  1. <?php
  2. namespace SparkLib\Xml;
  3. use \DOMDocument, \DOMElement;
  4. /** because DOMDocument sucks
  5. *
  6. * Builder is a wrapper for DOMDocument's creation interface.
  7. *
  8. * When using php's DOM library you are required to manually create a
  9. * series of DOMInterface and DOMDocument and DOMAttribute and and and
  10. * and and ...
  11. *
  12. * With SparkLib\Xml\Builder, you can instead just build out a series of
  13. * nested nodes using a simplified method chaining syntax similar to
  14. * XML builder clasess available elsewhere.
  15. *
  16. * SparkLib\Xml\Builder uses a subset of php's DOM functions so that
  17. * the restrictions imposed by standard practice aren't enforced by
  18. * the builder or DOM class.
  19. *
  20. * General usage:
  21. * $b = new \SparkLib\Xml\Builder();
  22. *
  23. * - Create elements using the object operator:
  24. * $b->Name('Rob')
  25. * ->Age('34')
  26. * ->Weight('185')
  27. *
  28. * to produce:
  29. * <Name>Rob</Name>
  30. * <Age>34</Age>
  31. * <Weight>185</Weight>
  32. *
  33. * - Add attributes to previous node using ->attribs :
  34. * $b->Person
  35. * ->attribs( array(
  36. * 'age' => 34,
  37. * 'weight' => 185,
  38. * ))
  39. *
  40. * to produce:
  41. * <Person age="34" weight="185"></Person>
  42. *
  43. * - Build out an independent or nested set of nodes using ->child()
  44. * and add them as children of a node :
  45. * $people = $b->child();
  46. * foreach (array('Rob','Casey','Brennen','Dave') as $name)
  47. * $people->$name;
  48. * $b->People($people);
  49. *
  50. * to produce[1]:
  51. * <People>
  52. * <Rob></Rob>
  53. * <Casey></Casey>
  54. * <Brennen></Brennen>
  55. * <Dave></Dave>
  56. * </People>
  57. *
  58. * - Add children to previous node using ->nest :
  59. * $b->People;
  60. * foreach (array('Rob','Casey','Brennen','Dave') as $name)
  61. * $b->nest( $b->child()->$name );
  62. *
  63. * to produce:
  64. * <People>
  65. * <Rob></Rob>
  66. * <Casey></Casey>
  67. * <Brennen></Brennen>
  68. * <Dave></Dave>
  69. * </People>
  70. *
  71. * - Fetch a string representation of the document :
  72. * print $b->People->Places->Things->string( $want_html );
  73. *
  74. * - Fetch the DOMDocument object for beating with hammers :
  75. * $b->Youll->Hate->Yourself->domodc();
  76. *
  77. *
  78. * Notes:
  79. * 1: Thankfully, DOMDocument doesn't know how to create singleton tags,
  80. * so it just creates empty tag pairs: <br></br>. D:
  81. */
  82. class Builder {
  83. private $domdoc;
  84. private $namespace = '';
  85. private $namespace_url = '';
  86. private $last_node = false;
  87. public function __construct(){
  88. $this->domdoc = new DOMDocument('1.0');
  89. }
  90. public function attribs( $attributes ){
  91. foreach ($attributes as $name => $value)
  92. $this->last_node()->setAttribute($name, $value);
  93. return $this;
  94. }
  95. public function child(){
  96. $x = new static;
  97. $x->xmlns($this->namespace, $this->namespace_url);
  98. return $x;
  99. }
  100. public function nest($document){
  101. if ($document == null)
  102. return $this;
  103. $node = $this->last_node();
  104. if ($document instanceof DOMDocument)
  105. $kids = $document;
  106. elseif ($document instanceof static)
  107. $kids = $document->domdoc;
  108. else
  109. throw new InvalidArgumentException(' nest only knows how to import children from a DOMDocument or a SparkLib\Xml\Builder.');
  110. if (count($kids) == 0)
  111. return $this;
  112. foreach ($kids->childNodes as $kid) {
  113. $node->appendChild(
  114. $this->domdoc->importNode($kid, true)
  115. );
  116. }
  117. return $this;
  118. }
  119. public function last_node(){
  120. $node = $this->last_node;
  121. if ($node === false)
  122. throw new \LogicException('Unable to set attributes for nonexistant previous node');
  123. return $node;
  124. }
  125. public function xmlns($namespace, $url){
  126. $this->namespace = $namespace;
  127. $this->namespace_url = $url;
  128. return $this;
  129. }
  130. public function node($name, $value = '', $attributes = array(), $children = null){
  131. if (strlen($this->namespace) > 0)
  132. $node = new DOMElement("{$this->namespace}:{$name}", '', $this->namespace_url);
  133. else
  134. $node = new DOMElement($name);
  135. $node->nodeValue = $value;
  136. $this->last_node = $node;
  137. $this->domdoc->appendChild($node);
  138. $this->attribs($attributes);
  139. $this->nest($children);
  140. return $this;
  141. }
  142. public function __get($name){
  143. $this->node($name);
  144. return $this;
  145. }
  146. public function __call($name, $arguments){
  147. if (count($arguments) <= 0) {
  148. $this->node($name);
  149. return $this;
  150. }
  151. $first = $arguments[0];
  152. if ($first instanceof static)
  153. $this->node($name, '', array(), $first->domdoc);
  154. elseif ($first instanceof DOMDocument)
  155. $this->node($name, '', array(), $first);
  156. else
  157. $this->node($name, $first);
  158. return $this;
  159. }
  160. public function domdoc(){
  161. return $this->domdoc;
  162. }
  163. public function string($html = false){
  164. if ($html)
  165. return $this->domdoc->saveHTML();
  166. else
  167. return $this->domdoc->saveXML();
  168. }
  169. }