7

I'm building a Geocoding class that can utilize multiple webservices for Geocoding (ie Google, Yahoo, Bing, etc.). I'm trying to make it in a such a way that new webservices can be easily configured. Most of the webservices return either XML/JSON.. for PHP I chose XML as my primary focus. All the code is already in place, but now Google for instance returns the following XML (transformed to a simple_xml_element)

SimpleXMLElement Object
 (
[status] => OK
[result] => Array
    (
        [0] => SimpleXMLElement Object
            (
                [type] => postal_code
                [formatted_address] => 1010 Lausanne, Switzerland
                [address_component] => Array
                    (
                        [0] => SimpleXMLElement Object
                            (
                                [long_name] => 1010
                                [short_name] => 1010
                                [type] => postal_code
                            )

                        [1] => SimpleXMLElement Object
                            (
                                [long_name] => Lausanne
                                [short_name] => Lausanne
                                [type] => Array
                                    (
                                        [0] => locality
                                        [1] => political
                                    )

                            )

                        [2] => SimpleXMLElement Object
                            (
                                [long_name] => Vaud
                                [short_name] => VD
                                [type] => Array
                                    (
                                        [0] => administrative_area_level_1
                                        [1] => political
                                    )

                            )

                        [3] => SimpleXMLElement Object
                            (
                                [long_name] => Switzerland
                                [short_name] => CH
                                [type] => Array
                                    (
                                        [0] => country
                                        [1] => political
                                    )

                            )

                    )

                [geometry] => SimpleXMLElement Object
                    (
                        [location] => SimpleXMLElement Object
                            (
                                [lat] => 46.5376186
                                [lng] => 6.6539665
                            )

                        [location_type] => APPROXIMATE
                        [viewport] => SimpleXMLElement Object
                            (
                                [southwest] => SimpleXMLElement Object
                                    (
                                        [lat] => 46.5253574
                                        [lng] => 6.6384420
                                    )

                                [northeast] => SimpleXMLElement Object
                                    (
                                        [lat] => 46.5467887
                                        [lng] => 6.6745222
                                    )

                            )

                        [bounds] => SimpleXMLElement Object
                            (
                                [southwest] => SimpleXMLElement Object
                                    (
                                        [lat] => 46.5253574
                                        [lng] => 6.6384420
                                    )

                                [northeast] => SimpleXMLElement Object
                                    (
                                        [lat] => 46.5467887
                                        [lng] => 6.6745222
                                    )

                            )

                    )

            )
)

The information I need is in the [location] tag, so I've tried storing the path in a var:

$lat_path = 'result[0]->geometry->location->lat;

And then try to access the value this way:

(suppose $xml is the object)
$xml->{$lat_path};

But this doens't work. Is there any way I can access the information dynamically or variable based. I do not want to ruin my Geocoding method with Google specific code.

Thanks!

3
  • Use SimpleXMLElement::xpath instead of the php objection notation. (if you can show some of the xml, I'll try to provide an example implementation) Commented Aug 12, 2011 at 8:16
  • You can write method for that and forget.. Commented Aug 12, 2011 at 8:16
  • I tried using Xpath also, but it didn't work :( print_r($xml->Xpath('geometry/location')); gave me an empty array. Commented Aug 12, 2011 at 8:57

3 Answers 3

3

When you do

$xml->{$lat_path};

PHP will use anything within $lat_path as the variable name. It will not go into the object graph or obey the T_OBJECT_OPERATOR at all. It will simply look for a property

 'result[0]->geometry->location->lat;'

in $xml. Try to run this code for an example:

$obj = new StdClass;
$obj->{'result[0]->geometry->location->lat;'} = 1;
print_r($obj);

It will output

stdClass Object
(
    [result[0]->geometry->location->lat;] => 1
)

As you can see, it is one single property, not a nested object graph.

Like suggested in the comments, either use XPath or go to the desired value directly:

$xml->result[0]->geometry->location->lat;
Sign up to request clarification or add additional context in comments.

Comments

3

If you're not able to use xPath and need to access a object dynamically, you can use the following approach:

$oObj = new StdClass;
$oObj->Root->Parent->ID = 1;
$oObj->Root->Parent->Child->ID = 2;

$sSeachInTree = 'Root\\Parent\\Child\\ID';
$aElements = explode("\\",$sSeachInTree);

foreach($aElements as $sElement)
{
    if (isset($oObj->{$sElement}))
    {
        if (end($aElements) == $sElement)       
        {
            echo "Found: " . $sElement . " = " . $oObj->{$sElement};
        }
        $oObj = $oObj->{$sElement};
    }
}

Comments

0

I ran into this issue today. Here was my solution.

<?php
  /**
 * Traverse an object by splitting the path in the argument
 * Only returns values that are in nested objects not arrays
 */
function get_property_from_nested_objects(object $object, string $path, $default_fallback = null)
{
    if (strpos($path, '->') !== false) {
        $path_properties = explode('->', $path);
    } else {
        return isset($object->$path) ? $object->$path : $default_fallback;
    }

    $nested_objects = [];

    foreach ($path_properties as $nested_obj_index => $object_key) {
        if (isset($object->$object_key) && is_object($object->$object_key)) {
            $nested_objects[$nested_obj_index] = $object->$object_key;
            continue;
        } elseif (isset($nested_objects[$nested_obj_index - 1]->$object_key) && is_object($nested_objects[$nested_obj_index - 1]->$object_key)) {
            $nested_objects[$nested_obj_index] = $nested_objects[$nested_obj_index - 1]->$object_key;
            continue;
        } elseif (isset($nested_objects[$nested_obj_index - 1]->$object_key) && !is_object($nested_objects[$nested_obj_index - 1]->$object_key)) {
            return $nested_objects[$nested_obj_index - 1]->$object_key;
        } else {
            return $default_fallback;
        }
    }
}

echo get_property_from_nested_objects((object)[
    'obj1' => (object) [
        'prop' => 'works'
    ] 
], 'obj1->prop');

// output: 'works'

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.