Example usage:
$xmlNode = simplexml_load_file('example.xml');
$arrayData = xmlToArray($xmlNode);
echo json_encode($arrayData);Read the blog post for more info.
License: Public domain
Example usage:
$xmlNode = simplexml_load_file('example.xml');
$arrayData = xmlToArray($xmlNode);
echo json_encode($arrayData);Read the blog post for more info.
License: Public domain
| <?php | |
| /** | |
| * Create plain PHP associative array from XML. | |
| * | |
| * Example usage: | |
| * $xmlNode = simplexml_load_file('example.xml'); | |
| * $arrayData = xmlToArray($xmlNode); | |
| * echo json_encode($arrayData); | |
| * | |
| * @param SimpleXMLElement $xml The root node | |
| * @param array $options Associative array of options | |
| * @return array | |
| * @link http://outlandishideas.co.uk/blog/2012/08/xml-to-json/ More info | |
| * @author Tamlyn Rhodes <http://tamlyn.org> | |
| * @license http://creativecommons.org/publicdomain/mark/1.0/ Public Domain | |
| */ | |
| function xmlToArray($xml, $options = array()) { | |
| $defaults = array( | |
| 'namespaceRecursive' => false, //setting to true will get xml doc namespaces recursively | |
| 'removeNamespace' => false, //set to true if you want to remove the namespace from resulting keys (recommend setting namespaceSeparator = '' when this is set to true) | |
| 'namespaceSeparator' => ':', //you may want this to be something other than a colon | |
| 'attributePrefix' => '@', //to distinguish between attributes and nodes with the same name | |
| 'alwaysArray' => array(), //array of xml tag names which should always become arrays | |
| 'autoArray' => true, //only create arrays for tags which appear more than once | |
| 'textContent' => '$', //key used for the text content of elements | |
| 'autoText' => true, //skip textContent key if node has no attributes or child nodes | |
| 'keySearch' => false, //optional search and replace on tag and attribute names | |
| 'keyReplace' => false //replace values for above search values (as passed to str_replace()) | |
| ); | |
| $options = array_merge($defaults, $options); | |
| $namespaces = $xml->getDocNamespaces($options['namespaceRecursive']); | |
| $namespaces[''] = null; //add base (empty) namespace | |
| //get attributes from all namespaces | |
| $attributesArray = array(); | |
| foreach ($namespaces as $prefix => $namespace) { | |
| if ($options['removeNamespace']) { | |
| $prefix = ''; | |
| } | |
| foreach ($xml->attributes($namespace) as $attributeName => $attribute) { | |
| //replace characters in attribute name | |
| if ($options['keySearch']) { | |
| $attributeName = | |
| str_replace($options['keySearch'], $options['keyReplace'], $attributeName); | |
| } | |
| $attributeKey = $options['attributePrefix'] | |
| . ($prefix ? $prefix . $options['namespaceSeparator'] : '') | |
| . $attributeName; | |
| $attributesArray[$attributeKey] = (string)$attribute; | |
| } | |
| } | |
| //get child nodes from all namespaces | |
| $tagsArray = array(); | |
| foreach ($namespaces as $prefix => $namespace) { | |
| if ($options['removeNamespace']) { | |
| $prefix = ''; | |
| } | |
| foreach ($xml->children($namespace) as $childXml) { | |
| //recurse into child nodes | |
| $childArray = xmlToArray($childXml, $options); | |
| $childTagName = key($childArray); | |
| $childProperties = current($childArray); | |
| //replace characters in tag name | |
| if ($options['keySearch']) { | |
| $childTagName = | |
| str_replace($options['keySearch'], $options['keyReplace'], $childTagName); | |
| } | |
| //add namespace prefix, if any | |
| if ($prefix) { | |
| $childTagName = $prefix . $options['namespaceSeparator'] . $childTagName; | |
| } | |
| if (!isset($tagsArray[$childTagName])) { | |
| //only entry with this key | |
| //test if tags of this type should always be arrays, no matter the element count | |
| $tagsArray[$childTagName] = | |
| in_array($childTagName, $options['alwaysArray'], true) || !$options['autoArray'] | |
| ? array($childProperties) : $childProperties; | |
| } elseif ( | |
| is_array($tagsArray[$childTagName]) && array_keys($tagsArray[$childTagName]) | |
| === range(0, count($tagsArray[$childTagName]) - 1) | |
| ) { | |
| //key already exists and is integer indexed array | |
| $tagsArray[$childTagName][] = $childProperties; | |
| } else { | |
| //key exists so convert to integer indexed array with previous value in position 0 | |
| $tagsArray[$childTagName] = array($tagsArray[$childTagName], $childProperties); | |
| } | |
| } | |
| } | |
| //get text content of node | |
| $textContentArray = array(); | |
| $plainText = trim((string)$xml); | |
| if ($plainText !== '') { | |
| $textContentArray[$options['textContent']] = $plainText; | |
| } | |
| //stick it all together | |
| $propertiesArray = !$options['autoText'] || $attributesArray || $tagsArray || ($plainText === '') | |
| ? array_merge($attributesArray, $tagsArray, $textContentArray) : $plainText; | |
| //return node as array | |
| return array( | |
| $xml->getName() => $propertiesArray | |
| ); | |
| } |