-
-
Save jasondmoss/7344311 to your computer and use it in GitHub Desktop.
<?php | |
/** | |
* Convert a SimpleXML object to an associative array | |
* | |
* @param object $xmlObject | |
* | |
* @return array | |
* @access public | |
*/ | |
function simpleXmlToArray($xmlObject) | |
{ | |
$array = []; | |
foreach ($xmlObject->children() as $node) { | |
$array[$node->getName()] = is_array($node) ? simplexml_to_array($node) : (string) $node; | |
} | |
return $array; | |
} |
_b
is_array($node)
returned false for me, so it only gave me results one layer down
Nice One...thanks
The enhanced version, with recursive children
function simpleXmlToArray($xmlObject)
{
$array = [];
foreach ($xmlObject->children() as $node) {
// check if there are children
if($node->count() > 0) {
$array[$node->getName()] = simpleXmlToArray($node);
continue;
}
$array[$node->getName()] = is_array($node) ? simplexml_to_array($node) : (string) $node;
}
return $array;
}
In few cases, an XML object can be in a form as showed below:
<sameParentNode>
<firstRecursiveNodes></firstRecursiveNodes>
</sameParent>
<sameParentNode>
<secondRecursiveNodes></secondRecursiveNodes>
</sameParentNode>
...
<sameParentNode>
<lastRecursiveNodes></lastRecursiveNodes>
</sameParentNode>
In this case, the good enhanced function simpleXmlToArray()
proposed by @feldsam transforms the XML in an array nesting all the sameParentNode's sons but it's not able to convert the recursive SimpleXMLElement because of getting an absent node name. This causes it pushes in the array just last recursiveSon node, overwriting all the others previous.
[sameParentNode] => Array
(
[0] => SimpleXMLElement Object (lastRecursiveNodes)
(
...
)
)
So, I propose a new version with an if condition on recursive nodes that keeps the not-associative nodes in the transfomed array:
function simpleXmlToArray($xmlObject)
{
$array = [];
$c=0;
foreach ($xmlObject->children() as $node) {
// Here the new if: check if children don't have a node name keeping them in the new structure as not-associative nodes
if($node->children()->count() > 0)
{
$array[$node->getName()][] = simpleXmlToArray($node);
}
else {
$array[$node->getName()] = (string) $node;
}
}
return $array;
}
Thanks everybody for chipping in here. I have taken the version from @MarcelloDM and added attributes
support and nested nodes are not always added under a numeric value but directly under it's parent name.
function simpleXmlToArray(SimpleXMLElement $xmlObject): array
{
$array = [];
foreach ($xmlObject->children() as $node) {
$attributes = [];
if ($node->attributes()) {
foreach ($node->attributes() as $name => $value) {
$attributes[$name] = (string)$value;
}
}
if ($node->children()->count() > 0) {
$data = array_merge($attributes, $this->simpleXmlToArray($node));
if (isset($array[$node->getName()])) {
if (!isset($array[$node->getName()][0])) {
$entry = $array[$node->getName()];
$array[$node->getName()] = [];
$array[$node->getName()][] = $entry;
}
$array[$node->getName()][] = $data;
} else {
$array[$node->getName()] = $data;
}
} else {
$array[$node->getName()] = (string)$node;
}
}
return $array;
}
Hi all, in the end, I used following from https://hotexamples.com/examples/-/-/simplexml_to_array/php-simplexml_to_array-function-examples.html, with some edits.
/**
* @param $xml
* @return array
* https://hotexamples.com/examples/-/-/simplexml_to_array/php-simplexml_to_array-function-examples.html
*/
public static function simplexmlToArray($xml)
{
$ar = array();
foreach ($xml->children() as $k => $v) {
$child = self::simplexmlToArray($v);
if (count($child) == 0) {
$child = (string) $v;
}
foreach ($v->attributes() as $ak => $av) {
if (!is_array($child)) {
$child = array("value" => $child);
}
$child[$ak] = (string) $av;
}
if (!array_key_exists($k, $ar)) {
$ar[$k] = $child;
} else {
if (!is_string($ar[$k]) && isset($ar[$k][0])) {
$ar[$k][] = $child;
} else {
$ar[$k] = array($ar[$k]);
$ar[$k][] = $child;
}
}
}
return $ar;
}
Will this give the expected result?
json_decode(json_encode($xml), true);
Will this give the expected result?
json_decode(json_encode($xml), true);
This one did work for me (saw a similar line online) as it kept the inner XML so they ended up being blank
Hi all, in the end, I used following from https://hotexamples.com/examples/-/-/simplexml_to_array/php-simplexml_to_array-function-examples.html, with some edits.
/** * @param $xml * @return array * https://hotexamples.com/examples/-/-/simplexml_to_array/php-simplexml_to_array-function-examples.html */ public static function simplexmlToArray($xml) { $ar = array(); foreach ($xml->children() as $k => $v) { $child = self::simplexmlToArray($v); if (count($child) == 0) { $child = (string) $v; } foreach ($v->attributes() as $ak => $av) { if (!is_array($child)) { $child = array("value" => $child); } $child[$ak] = (string) $av; } if (!array_key_exists($k, $ar)) { $ar[$k] = $child; } else { if (!is_string($ar[$k]) && isset($ar[$k][0])) { $ar[$k][] = $child; } else { $ar[$k] = array($ar[$k]); $ar[$k][] = $child; } } } return $ar; }
This worked great, even on my XML that had many sub nodes.
Hi all, in the end, I used following from https://hotexamples.com/examples/-/-/simplexml_to_array/php-simplexml_to_array-function-examples.html, with some edits.
/** * @param $xml * @return array * https://hotexamples.com/examples/-/-/simplexml_to_array/php-simplexml_to_array-function-examples.html */ public static function simplexmlToArray($xml) { $ar = array(); foreach ($xml->children() as $k => $v) { $child = self::simplexmlToArray($v); if (count($child) == 0) { $child = (string) $v; } foreach ($v->attributes() as $ak => $av) { if (!is_array($child)) { $child = array("value" => $child); } $child[$ak] = (string) $av; } if (!array_key_exists($k, $ar)) { $ar[$k] = $child; } else { if (!is_string($ar[$k]) && isset($ar[$k][0])) { $ar[$k][] = $child; } else { $ar[$k] = array($ar[$k]); $ar[$k][] = $child; } } } return $ar; }
That works like a charm. Thanks!
I refactored it to be more readable -> tested on php 8.3 + changed how attributes are stored
/**
* Converts a SimpleXMLElement object to an associative array.
*/
public static function simpleXmlToArray(?SimpleXMLElement $xml): array|string {
if ($xml === null) {
return [];
}
$result = [];
foreach ($xml->attributes() as $attrName => $attrValue) {
$result['@attributes'][$attrName] = (string) $attrValue;
}
foreach ($xml->children() as $childName => $childElement) {
$childArray = self::simpleXmlToArray($childElement);
if (!isset($result[$childName])) {
$result[$childName] = $childArray;
continue;
}
if (!is_array($result[$childName]) || !array_is_list($result[$childName])) {
$result[$childName] = [$result[$childName]];
}
$result[$childName][] = $childArray;
}
$textContent = trim((string) $xml);
if (empty($result)) {
return $textContent;
}
if ($textContent !== '') {
$result['@value'] = $textContent;
}
return $result;
}
Thanx @Harfusha , saved me lot of time !
Thanks for having this when even stack overflow couldn't help, saved me quite a headache