Created
September 9, 2020 17:26
-
-
Save noah-st-amand/da242eabc2ebca33dd1e32c44bd90594 to your computer and use it in GitHub Desktop.
XML to Array (with namespaced elements)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Given the URL of an XML file, fetch the contents and pass it to _xml_to_array() to be | |
* converted to an associative array. The file is read into a string and then parsed via | |
* simplexml_load_string() (rather than parsed directly with simplexml_load_file()), | |
* because the "LIBXML_NOCDATA" parameter is required in order for CDATA to persist. | |
*/ | |
function _xml_to_array_from_file($url) { | |
$array = NULL; | |
if ($file = file_get_contents($url)) { | |
if ($xml = simplexml_load_string($file, 'SimpleXMLElement', LIBXML_NOCDATA)) $array = _xml_to_array($xml); | |
} | |
return $array; | |
} | |
/** | |
* Convert XML to an associative array, including all namespaced XML elements. Simplified | |
* and updated from https://outlandish.com/blog/tutorial/xml-to-json/ | |
*/ | |
function _xml_to_array($xml, $safe_key_prefix = '_xml_to_array') { | |
$array = []; | |
$name = $xml->getName(); | |
$namespaces = $xml->getDocNamespaces(); | |
$namespaces[''] = NULL; | |
// Get attributes from all namespaces. | |
$attributes = []; | |
foreach ($namespaces as $prefix => $namespace) { | |
foreach ($xml->attributes($namespace) as $attribute_name => $attribute) { | |
if ($prefix) $attribute_name = "{$prefix}:{$attribute_name}"; | |
$attributes[$attribute_name] = (string)$attribute; | |
} | |
} | |
// Get child nodes from all namespaces. | |
$tags = []; | |
foreach ($namespaces as $prefix => $namespace) { | |
foreach ($xml->children($namespace) as $child_xml) { | |
// Recurse into child nodes. | |
$child_array = _xml_to_array($child_xml); | |
$child_name = key($child_array); | |
$child_properties = current($child_array); | |
if ($prefix) $child_name = "{$prefix}:{$child_name}"; | |
if (!isset($tags[$child_name])) $tags[$child_name] = $child_properties; | |
else { | |
// This is a child element being added to a parent for which at least one simlar | |
// child element already exists. If only one child already exists, that existing | |
// child is directly under the parent, and thus needs to be converted to the first | |
// item in an array of children before the current element can be appended. In | |
// order to determine if this is the case, check if the key of the first child of | |
// the parent is "0", which indicates that there is already an array of children. | |
// If there's not already an array of children, the first key will be the key of | |
// an element within the lone child (e.g., "['title' => ...]"). | |
if (array_key_first($tags[$child_name]) !== 0) $tags[$child_name] = [0 => $tags[$child_name]]; | |
$tags[$child_name][] = $child_properties; | |
} | |
} | |
} | |
// Get the content of the node. | |
$content = []; | |
$content_string = trim((string)$xml); | |
if ($content_string !== '') $content["{$safe_key_prefix}_content"] = $content_string; | |
if (!empty($attributes) || (!empty($tags)) || ($content_string === '')) $properties = array_merge($attributes, $tags, $content); | |
else $properties = $content_string; | |
$array[$name] = $properties; | |
return $array; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment