Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert PHP array from XML that contains duplicate elements

Tags:

arrays

php

xml

Up until now, I've been using the snippet below to convert an XML tree to an array:

$a = json_decode(json_encode((array) simplexml_load_string($xml)),1);

..however, I'm now working with an XML that has duplicate key values, so the array is breaking when it loops through the XML. For example:

<users>
    <user>x</user>
    <user>y</user>
    <user>z</user>
</users>

Is there a better method to do this that allows for duplicate Keys, or perhaps a way to add an incremented value to each key when it spits out the array, like this:

$array = array(
    users => array(
        user_1 => x,
        user_2 => y,
        user_3 => z
    )
)

I'm stumped, so any help would be very appreciated.

like image 545
fireinspace Avatar asked Aug 02 '15 12:08

fireinspace


1 Answers

Here is a complete universal recursive solution.

This class will parse any XML under any structure, with or without tags, from the simplest to the most complex ones.

It retains all proper values and convert them (bool, txt or int), generates adequate array keys for all elements groups including tags, keep duplicates elements etc etc...

Please forgive the statics, it s part of a large XML tools set I used, before rewriting them all for HHVM or pthreads, I havent got time to properly construct this one, but it will work like a charm for straightforward PHP.

For tags, the declared value is '@attr' in this case but can be whatever your needs are.

$xml = "<body>
             <users id='group 1'>
               <user>x</user>
               <user>y</user>
               <user>z</user>
             </users>
            <users id='group 2'>
               <user>x</user>
               <user>y</user>
               <user>z</user>
            </users>
        </body>";

$result = xml_utils::xml_to_array($xml);

result:

Array ( [users] => Array ( [0] => Array ( [user] => Array ( [0] => x [1] => y [2] => z ) [@attr] => Array ( [id] => group 1 ) ) [1] => Array ( [user] => Array ( [0] => x [1] => y [2] => z ) [@attr] => Array ( [id] => group 2 ) ) ) )

Class:

class xml_utils {

    /*object to array mapper */
    public static function objectToArray($object) {
        if (!is_object($object) && !is_array($object)) {
            return $object;
        }
        if (is_object($object)) {
            $object = get_object_vars($object);
        }
        return array_map('objectToArray', $object);
    }

    /* xml DOM loader*/
    public static function xml_to_array($xmlstr) {
        $doc = new DOMDocument();
        $doc->loadXML($xmlstr);
        return xml_utils::dom_to_array($doc->documentElement);
    }

    /* recursive XMl to array parser */
    public static function dom_to_array($node) {
        $output = array();
        switch ($node->nodeType) {
            case XML_CDATA_SECTION_NODE:
            case XML_TEXT_NODE:
                $output = trim($node->textContent);
                break;
            case XML_ELEMENT_NODE:
                for ($i = 0, $m = $node->childNodes->length; $i < $m; $i++) {
                    $child = $node->childNodes->item($i);
                    $v = xml_utils::dom_to_array($child);
                    if (isset($child->tagName)) {
                        $t = xml_utils::ConvertTypes($child->tagName);
                        if (!isset($output[$t])) {
                            $output[$t] = array();
                        }
                        $output[$t][] = $v;
                    } elseif ($v) {
                        $output = (string) $v;
                    }
                }
                if (is_array($output)) {
                    if ($node->attributes->length) {
                        $a = array();
                        foreach ($node->attributes as $attrName => $attrNode) {
                            $a[$attrName] = xml_utils::ConvertTypes($attrNode->value);
                        }
                        $output['@attr'] = $a;
                    }
                    foreach ($output as $t => $v) {
                        if (is_array($v) && count($v) == 1 && $t != '@attr') {
                            $output[$t] = $v[0];
                        }
                    }
                }
                break;
        }
        return $output;
    }

    /* elements converter */
    public static function ConvertTypes($org) {
        if (is_numeric($org)) {
            $val = floatval($org);
        } else {
            if ($org === 'true') {
                $val = true;
            } else if ($org === 'false') {
                $val = false;
            } else {
                if ($org === '') {
                    $val = null;
                } else {
                    $val = $org;
                }
            }
        }
        return $val;
    }

}
like image 116
cpugourou Avatar answered Nov 15 '22 00:11

cpugourou