Skip to content

Instantly share code, notes, and snippets.

@mtvbrianking
Last active July 14, 2018 07:39
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 mtvbrianking/9b9b48b86d496a54fc5a15705b7daa02 to your computer and use it in GitHub Desktop.
Save mtvbrianking/9b9b48b86d496a54fc5a15705b7daa02 to your computer and use it in GitHub Desktop.
Convert XML to Array - Using a decorator
<?php
/**
* Class JsonSimpleXMLElementDecorator
*
* @link https://hakre.wordpress.com/2013/07/09/simplexml-and-json-encode-in-php-part-i/
*
* Implement JsonSerializable for SimpleXMLElement as a Decorator
*/
class JsonSimpleXMLElementDecorator implements JsonSerializable
{
const DEF_DEPTH = 512;
/**
* @var SimpleXMLElement
*/
private $subject;
private $options = ['@attributes' => TRUE, '@text' => TRUE, 'depth' => self::DEF_DEPTH];
public function __construct(SimpleXMLElement $element, $useAttributes = TRUE, $useText = TRUE, $depth = self::DEF_DEPTH)
{
$this->subject = $element;
if (!is_null($useAttributes)) {
$this->useAttributes($useAttributes);
}
if (!is_null($useText)) {
$this->useText($useText);
}
if (!is_null($depth)) {
$this->setDepth($depth);
}
}
public function useAttributes($bool)
{
$this->options['@attributes'] = (bool)$bool;
}
public function useText($bool)
{
$this->options['@text'] = (bool)$bool;
}
public function setDepth($depth)
{
$this->options['depth'] = (int)max(0, $depth);
}
/**
* Specify data which should be serialized to JSON
*
* @return mixed data which can be serialized by json_encode.
*/
public function jsonSerialize()
{
$subject = $this->subject;
$array = array();
// json encode attributes if any.
if ($this->options['@attributes']) {
if ($attributes = $subject->attributes()) {
$array['@attributes'] = array_map('strval', iterator_to_array($attributes));
}
}
// traverse into children if applicable
$children = $subject;
$this->options = (array)$this->options;
$depth = $this->options['depth'] - 1;
if ($depth <= 0) {
$children = [];
}
// json encode child elements if any. group on duplicate names as an array.
foreach ($children as $name => $element) {
/* @var SimpleXMLElement $element */
$decorator = new self($element);
$decorator->options = ['depth' => $depth] + $this->options;
if (isset($array[$name])) {
if (!is_array($array[$name])) {
$array[$name] = [$array[$name]];
}
$array[$name][] = $decorator;
} else {
$array[$name] = $decorator;
}
}
// json encode non-whitespace element simplexml text values.
$text = trim($subject);
if (strlen($text)) {
if ($array) {
$this->options['@text'] && $array['@text'] = $text;
} else {
$array = $text;
}
}
// return empty elements as NULL (self-closing or empty tags)
if (!$array) {
$array = NULL;
}
return $array;
}
}
$xml = <<<XML
<?xml version="1.0" encoding="UTF-8" ?>
<root doc="profile">
<!-- This is a comment... -->
<first_name>Brian</first_name>
<middle_name></middle_name>
<last_name>Matovu</last_name>
<languages>Luganda</languages>
<languages>English</languages>
<website>
<![CDATA[http://bmatovu.com]]>
</website>
<frameworks>
<php>Laravel</php>
<php>Slim</php>
<python>django</python>
</frameworks>
<accounts>
<username>brian-admin</username>
<role>admin</role>
</accounts>
<accounts>
<username>bmatovu</username>
<role>supervisor</role>
</accounts>
<packages>
<multi-auth>
<language>php</language>
<frameworks>laravel</frameworks>
<home-page>
<![CDATA[https://github.com/mtvbrianking/multi-auth]]>
</home-page>
</multi-auth>
<laravel-xml>
<language>php</language>
<framework>laravel</framework>
<home-page>
<![CDATA[https://github.com/mtvbrianking/laravel-xml]]>
</home-page>
</laravel-xml>
</packages>
</root>
XML;
$_obj = simplexml_load_string($xml);
$obj = new JsonSimpleXMLElementDecorator($_obj);
// print_r($obj);
// print json_encode($obj, true);
print json_encode([$_obj->getName() => $obj], true);
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment