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

<?php
namespace SparkLib\Xml;
use \DOMDocument, \DOMElement;
/** because DOMDocument sucks
*
* Builder is a wrapper for DOMDocument's creation interface.
*
* When using php's DOM library you are required to manually create a
* series of DOMInterface and DOMDocument and DOMAttribute and and and
* and and ...
*
* With SparkLib\Xml\Builder, you can instead just build out a series of
* nested nodes using a simplified method chaining syntax similar to
* XML builder clasess available elsewhere.
*
* SparkLib\Xml\Builder uses a subset of php's DOM functions so that
* the restrictions imposed by standard practice aren't enforced by
* the builder or DOM class.
*
* General usage:
* $b = new \SparkLib\Xml\Builder();
*
* - Create elements using the object operator:
* $b->Name('Rob')
* ->Age('34')
* ->Weight('185')
*
* to produce:
* <Name>Rob</Name>
* <Age>34</Age>
* <Weight>185</Weight>
*
* - Add attributes to previous node using ->attribs :
* $b->Person
* ->attribs( array(
* 'age' => 34,
* 'weight' => 185,
* ))
*
* to produce:
* <Person age="34" weight="185"></Person>
*
* - Build out an independent or nested set of nodes using ->child()
* and add them as children of a node :
* $people = $b->child();
* foreach (array('Rob','Casey','Brennen','Dave') as $name)
* $people->$name;
* $b->People($people);
*
* to produce[1]:
* <People>
* <Rob></Rob>
* <Casey></Casey>
* <Brennen></Brennen>
* <Dave></Dave>
* </People>
*
* - Add children to previous node using ->nest :
* $b->People;
* foreach (array('Rob','Casey','Brennen','Dave') as $name)
* $b->nest( $b->child()->$name );
*
* to produce:
* <People>
* <Rob></Rob>
* <Casey></Casey>
* <Brennen></Brennen>
* <Dave></Dave>
* </People>
*
* - Fetch a string representation of the document :
* print $b->People->Places->Things->string( $want_html );
*
* - Fetch the DOMDocument object for beating with hammers :
* $b->Youll->Hate->Yourself->domodc();
*
*
* Notes:
* 1: Thankfully, DOMDocument doesn't know how to create singleton tags,
* so it just creates empty tag pairs: <br></br>. D:
*/
class Builder {
private $domdoc;
private $namespace = '';
private $namespace_url = '';
private $last_node = false;
public function __construct(){
$this->domdoc = new DOMDocument('1.0');
}
public function attribs( $attributes ){
foreach ($attributes as $name => $value)
$this->last_node()->setAttribute($name, $value);
return $this;
}
public function child(){
$x = new static;
$x->xmlns($this->namespace, $this->namespace_url);
return $x;
}
public function nest($document){
if ($document == null)
return $this;
$node = $this->last_node();
if ($document instanceof DOMDocument)
$kids = $document;
elseif ($document instanceof static)
$kids = $document->domdoc;
else
throw new InvalidArgumentException(' nest only knows how to import children from a DOMDocument or a SparkLib\Xml\Builder.');
if (count($kids) == 0)
return $this;
foreach ($kids->childNodes as $kid) {
$node->appendChild(
$this->domdoc->importNode($kid, true)
);
}
return $this;
}
public function last_node(){
$node = $this->last_node;
if ($node === false)
throw new \LogicException('Unable to set attributes for nonexistant previous node');
return $node;
}
public function xmlns($namespace, $url){
$this->namespace = $namespace;
$this->namespace_url = $url;
return $this;
}
public function node($name, $value = '', $attributes = array(), $children = null){
if (strlen($this->namespace) > 0)
$node = new DOMElement("{$this->namespace}:{$name}", '', $this->namespace_url);
else
$node = new DOMElement($name);
$node->nodeValue = $value;
$this->last_node = $node;
$this->domdoc->appendChild($node);
$this->attribs($attributes);
$this->nest($children);
return $this;
}
public function __get($name){
$this->node($name);
return $this;
}
public function __call($name, $arguments){
if (count($arguments) <= 0) {
$this->node($name);
return $this;
}
$first = $arguments[0];
if ($first instanceof static)
$this->node($name, '', array(), $first->domdoc);
elseif ($first instanceof DOMDocument)
$this->node($name, '', array(), $first);
else
$this->node($name, $first);
return $this;
}
public function domdoc(){
return $this->domdoc;
}
public function string($html = false){
if ($html)
return $this->domdoc->saveHTML();
else
return $this->domdoc->saveXML();
}
}