Skip to content

Instantly share code, notes, and snippets.

@jasondmoss
Last active June 22, 2022 21:12
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save jasondmoss/7344311 to your computer and use it in GitHub Desktop.
Save jasondmoss/7344311 to your computer and use it in GitHub Desktop.
Convert a SimpleXML object to associative array
<?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;
}
@ncovercash
Copy link

Thanks for having this when even stack overflow couldn't help, saved me quite a headache

@samuelwilliams
Copy link

_b

@samjross
Copy link

is_array($node) returned false for me, so it only gave me results one layer down

@nabaasa
Copy link

nabaasa commented Jun 14, 2020

Nice One...thanks

@feldsam
Copy link

feldsam commented Sep 13, 2020

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;
    }

@MarcelloDM
Copy link

MarcelloDM commented Sep 18, 2020

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;
}

@roland-d
Copy link

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;
    }

@feldsam
Copy link

feldsam commented Dec 28, 2020

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;
    }

@iamvar
Copy link

iamvar commented Jan 6, 2021

Will this give the expected result?

json_decode(json_encode($xml), true);

@carnini
Copy link

carnini commented Mar 12, 2021

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

@carnini
Copy link

carnini commented Mar 12, 2021

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment