Skip to content

Instantly share code, notes, and snippets.

@hakre
Created November 4, 2012 16:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hakre/4012538 to your computer and use it in GitHub Desktop.
Save hakre/4012538 to your computer and use it in GitHub Desktop.
Convert/Import an Array into a SimpleXMLElement
/**
* Convert/Import an Array into a SimpleXMLElement
*
* @author hakre <http://hakre.wordpress.com/>
* @see http://stackoverflow.com/a/13219372/367456 for usage examples
*/
class SimpleXMLArrayImport
{
const TYPE_INVALID = 0;
const TYPE_EMPTY = 1;
const TYPE_VALUE = 2;
const TYPE_NAMED = 3;
const TYPE_LIST = 4;
private $doc;
public function __construct(array $data = array()) {
$data && $this->importArray($data);
}
public function getDocument() {
if (!$this->hasDocument()) {
throw new BadMethodCallException('No SimpleXML document has been created or assigned so far.');
}
return $this->doc;
}
public function setDocument(SimpleXMLElement $doc) {
list($root) = $doc->xpath('/*');
$this->doc = $root;
}
public function hasDocument() {
return $this->doc instanceof SimpleXMLElement;
}
/**
* Create a new SimpleXML document out of an array
*
* @param array $array
* @return SimpleXMLElement root element
* @throws InvalidArgumentException
*/
public function importArray(array $array) {
$count = count($array);
if ($count !== 1) {
throw new InvalidArgumentException(sprintf('Array must have exactly one root element, %d given.', $count));
}
list($name, $children) = each($array);
$xml = new SimpleXMLElement(sprintf('<%s/>', $name));
$this->addNode($xml, $children);
$this->doc = $xml;
return $xml;
}
public function addArray(SimpleXMLElement $parent, array $array) {
list($this->doc) = $parent->xpath('/*');
return $this->addNode($parent, $array);
}
/**
* @param SimpleXMLElement $parent
* @param $node
* @return SimpleXMLElement The last element added. If a value content or an empty element was added
* returns the parent.
* @throws InvalidArgumentException
*/
private function addNode(SimpleXMLElement $parent, $node) {
$type = $this->getType($node);
$added = NULL;
switch ($type) {
case self::TYPE_VALUE:
$parent->{0} = (string)$node; # fall-through intended
case self::TYPE_EMPTY:
$added = $parent;
break;
case self::TYPE_NAMED:
foreach ($node as $name => $child) {
$added = $this->addChild($parent, $name, $child);
}
break;
case self::TYPE_LIST:
foreach ($node as $name => $children) {
$added = $this->addChildren($parent, $name, $children);
}
break;
default:
throw new InvalidArgumentException('Invalid Node Type');
}
return $added;
}
/**
* add child element
*/
private function addChild(SimpleXMLElement $parent, $name, $node) {
$element = $parent->addChild($name);
$this->addNode($element, $node);
return $element;
}
/**
* add multiple children with the same name
*/
private function addChildren(SimpleXMLElement $parent, $name, array $children) {
foreach ($children as $child) {
$element = $this->addChild($parent, $name, $child);
}
return $element;
}
private function getType($node) {
if (!is_array($node)) {
return self::TYPE_VALUE;
}
$keys = array_keys($node);
if (!$keys) {
return self::TYPE_EMPTY;
}
if ($keys[0] === 0) {
return self::TYPE_INVALID;
}
if (isset($node[$keys[0]][0])) {
return self::TYPE_LIST;
}
return self::TYPE_NAMED;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment