86

I came across this function of converting a SimpleXML Object to an array here:

/**
 * function object2array - A simpler way to transform the result into an array 
 *   (requires json module).
 *
 * This function is part of the PHP manual.
 *
 * The PHP manual text and comments are covered by the Creative Commons 
 * Attribution 3.0 License, copyright (c) the PHP Documentation Group
 *
 * @author  Diego Araos, diego at klapmedia dot com
 * @date    2011-02-05 04:57 UTC
 * @link    http://www.php.net/manual/en/function.simplexml-load-string.php#102277
 * @license http://www.php.net/license/index.php#doc-lic
 * @license http://creativecommons.org/licenses/by/3.0/
 * @license CC-BY-3.0 <http://spdx.org/licenses/CC-BY-3.0>
 */
function object2array($object)
{
    return json_decode(json_encode($object), TRUE); 
}

So my adoption for an XML strings is like:

function xmlstring2array($string)
{
    $xml   = simplexml_load_string($string, 'SimpleXMLElement', LIBXML_NOCDATA);

    $array = json_decode(json_encode($xml), TRUE);

    return $array;
}

It works pretty well, but it seems a bit hacky? Is there a more efficient/robust way of doing this?

I know that the SimpleXML Object is close enough to an array because it makes use of the ArrayAccess interface in PHP but it still doesn't work great to use as an array with multi-dimensional arrays i.e. looping.

Thanks all for any help

hakre
  • 193,403
  • 52
  • 435
  • 836
Abs
  • 56,052
  • 101
  • 275
  • 409
  • 2
    What's the reason for it? Is it looping? Because in that case you should be able to loop parts of the SimpleXMLElement object without any problems. For example if you're parsing an ATOM feed with SimpleXML you'd be able to do the following: `foreach($xml->entry as $entry)` and then access `$entry->title` et.c. from within the loop. – Karl Laurentius Roos May 29 '11 at 10:57
  • 1
    Note that adding `(array)` to the above (i.e. `@json_decode(@json_encode((array)$simple_xml_object ), 1);`) as noted in a later comment in the PHP manual may cause `Node no longer exists` errors. – Halil Özgür Mar 20 '13 at 16:40
  • what's this question about? json_encode does tree traversal on the simplexml element. What did you expect differently? How do you define "a bit hacky"? What is not robust with this approach in your eyes? What is not efficient? – hakre Jul 08 '13 at 07:31
  • 3
    This question is clear to me, so I recommend reopening it. – Dan Nissenbaum Jul 15 '14 at 14:25
  • This is what I use https://stackoverflow.com/a/65863059/1319363 – ronline Jan 23 '21 at 19:28

2 Answers2

98

I found this in the PHP manual comments:

/**
 * function xml2array
 *
 * This function is part of the PHP manual.
 *
 * The PHP manual text and comments are covered by the Creative Commons 
 * Attribution 3.0 License, copyright (c) the PHP Documentation Group
 *
 * @author  k dot antczak at livedata dot pl
 * @date    2011-04-22 06:08 UTC
 * @link    http://www.php.net/manual/en/ref.simplexml.php#103617
 * @license http://www.php.net/license/index.php#doc-lic
 * @license http://creativecommons.org/licenses/by/3.0/
 * @license CC-BY-3.0 <http://spdx.org/licenses/CC-BY-3.0>
 */
function xml2array ( $xmlObject, $out = array () )
{
    foreach ( (array) $xmlObject as $index => $node )
        $out[$index] = ( is_object ( $node ) ) ? xml2array ( $node ) : $node;

    return $out;
}

It could help you. However, if you convert XML to an array you will loose all attributes that might be present, so you cannot go back to XML and get the same XML.

hakre
  • 193,403
  • 52
  • 435
  • 836
Arjan
  • 9,784
  • 1
  • 31
  • 41
  • 16
    Note that this doesn't convert multidimensional objects into pure arrays, i.e. the child elements are still `SimpleXMLElement`s. This is because `is_object($node)` returns `false` for child objects, i.e. `gettype($node)` inside second recursion is `"array"`. A more proper method is [the comment just below it](http://www.php.net/manual/en/ref.simplexml.php#111227). The second method carries some performance implications when compared against the first (original) one and and against the json method: http://codepad.viper-7.com/eHhSNR, which makes json method usable again performance-wise – Halil Özgür Mar 20 '13 at 16:24
  • 2
    @Arjan: You missed to do proper attribution of copyright holders and the author. I also added some licensing docblock tags for convenient reasons. Please take care when you copy over code-examples from the PHP manual here on the website. They are compatible from the license, but they require attribution. As CC are not specifically designed for software, the code-examples are most likely not usable in real-life occasions, they are just usable to show/explain something. If you do not attribute and hide the copyright holders, this often gets lost. – hakre Jul 08 '13 at 08:09
  • 2
    this function not work recursive. here is a better version: http://stackoverflow.com/questions/2726487/simplexmlelement-to-php-array/24919807#24919807 – Bo Pennings Jul 23 '14 at 19:58
  • Is possible to convert Object to XML? @Arjan – Gem Nov 16 '18 at 06:51
  • As @HalilÖzgür said, it wouldn't convert an array of `SimpleXMLElement`s. Althought it can be fixed using ```$out[$index] = is_object($node) || is_array($node) ? xml2array($node) : $element;``` So it will go deeper even if it's an array – Javier S Apr 30 '19 at 22:43
  • public function xml2array ( $xmlObject, $out = array () ) { foreach ( (array) $xmlObject as $index => $node ) //$out[$index] = ( is_object ( $node ) ) ? xml2array ( $node ) : $node; $out[$index] = is_object($node) || is_array($node) ? self::xml2array($node) : $node; return $out; } – Ruthe Mar 04 '20 at 05:02
  • @JavierS instead of ```$element``` I think you mean ```$node```? – nxasdf Nov 25 '22 at 04:50
84

Just (array) is missing in your code before the simplexml object:

...

$xml   = simplexml_load_string($string, 'SimpleXMLElement', LIBXML_NOCDATA);

$array = json_decode(json_encode((array)$xml), TRUE);
                                 ^^^^^^^
...
hakre
  • 193,403
  • 52
  • 435
  • 836
  • 3
    CDATA content goes missing with this approach. Tested with PHP 5.5.21 – Wouter Jul 27 '15 at 09:08
  • 6
    You don't have to use `json_**code`. Simply use `(object) (array) $xml` and it's done! ;-) – Monkey Monk Sep 16 '15 at 10:26
  • 10
    @MonkeyMonk that's only true if XML has "flat" structure. WARNING! using `json_**` for getting an array will produce different results depending on number of child objects (one vs multiple). – jmarceli Dec 24 '15 at 13:06
  • @jmarceli Good point and good to know ! ;-) Ty ! – Monkey Monk Dec 28 '15 at 09:42
  • yes json encode/decode isn't necessary as pointed out above $data = (array)simplexml_load_string($xml); – TURTLE Apr 25 '18 at 16:24
  • Nice! This helped me! – Ingus Jul 17 '19 at 09:39
  • I know it seems like overkill for the json_decode/encode, but this did actually work for me when omitting the json calls did not. Specifically for XML with lots of nested tags. – Richard Oct 10 '22 at 23:01