views:

91

answers:

2
<?php
/*
    Sample: $results = XMLParser::load('<xml ....');
            $results = XMLParser::load(VSCHEMAS.'/Users.edit.xml');
*/

    /**
     * Abstract XMLParser class. A non-instantiable class that uses SimpleXML to parse XML, based on a path or body passed into the load method
     * 
     * @abstract
     */
    abstract class XMLParser {

        /**
         * convert function. Converts a SimpleXMLElement object to an associative array, usable for iteration
         * 
         * @see http://www.if-not-true-then-false.com/2009/12/php-tip-convert-stdclass-object-to-multidimensional-array-and-convert-multidimensional-array-to-stdclass-object/
         * @access private
         * @static
         * @param mixed $node node to convert to a non-object based value
         * @return array associative array of the passed in node/object, ultimately representing the initially passed in object as an associative array
         */
        private static function convert($node) {
            if(is_object($node))
                $node = get_object_vars($node);
            if(is_array($node))
                return array_map(array('self', 'convert'), $node);
            return $node;
        }

        /**
         * load function. Loads a source (either a local path or source body) document, and returns as associative array of it's results
         * 
         * @access public
         * @static
         * @param string $source xml body, or path to local xml file
         * @return array SimpleXML results, parsed as an associative array
         */
        public static function load($source) {
            $path = false;
            if(preg_match('/^\//', $source) > 0)
                $path = true;
            $simpleXMLElement = new SimpleXMLElement($source, LIBXML_NOENT, $path);
            return self::convert($simpleXMLElement);
        }
    }

?>

I'm using the above code to parse xml files and convert them to a more traversable array. I'm running into an issue though. When I have some sample xml like:

<fields>
    <rule whatever="lolcats" />
</fields>

vs.

<fields>
    <rule whatever="lolcats" />
    <rule whatever="lolcats" />
</fields>

the resulting array isn't consistent. Namely, in the first case, it's of the format:

Array
(
    [field] => Array
        (
            [@attributes]...

Whereas in the latter, it's of the format:

Array
(
    [field] => Array
        (
            [0]...

What I'm saying here, is that it's indexing the sub-xml elements numerically, which is what I want, but only when there is more than 1. Any thoughts on what to change to always have them indexed numerically, rather than a direct reference to the one-and-only element's @attributes array?

Any help would be much appreciated :D

A: 

Well you cant have an element or a attrib that is an int so simply testing for the array key 0 and then forging the array you expect should work.

prodigitalson
i tried that. the convert function gets really messy really quick. any other thoughts?
onassar
A: 

boom! i played around with the bit of code below for a couple hours, and finally knocked it out of the editor! the trick was to loop through the vars with the value's being references, and if it was indeed an object, but the key wasn't '@attributes' (as mentioned above) then wrap it in an array :D

/**
 * convert function. Converts a SimpleXMLElement object to an associative array, usable for iteration
 * 
 * @see http://www.if-not-true-then-false.com/2009/12/php-tip-convert-stdclass-object-to-multidimensional-array-and-convert-multidimensional-array-to-stdclass-object/
 * @access private
 * @static
 * @param mixed $node node to convert to a non-object based value
 * @return array associative array of the passed in node/object, ultimately representing the initially passed in object as an associative array
 */
private static function convert($node) {
    if(is_object($node)) {
        $vars = get_object_vars($node);
        foreach($vars as $key => &$var) {
            if($key!=='@attributes' && is_object($var))
                $var = array($var);
        }
        $node = $vars;
    }
    if(is_array($node))
        return array_map(array('self', 'convert'), $node);
    return $node;
}
onassar