Jump to content

Iteration over JSON response DOM tree


dmsinc

Recommended Posts

Evening everyone and Merry X-Mas (Happy Holidays) or whatever fits you best....   I have been trying over and over for about 12 hours to figure out how to get data from a specific JSON response and assign the specific values to a new array key/value pair. The various ways I have tried to figure this out are  numerous so i'm going to avoid the runnig list of "I trieid this...and this...and this... etc etc." just understand I have reached a dead end point where I need help badly.

 

Here is what our end goal is:

 

"The company" is a "service industry" provider (plumbing, electrical etc. etc.) who wants to dispatch its technicians to new jobs based on which technician has the shortest travel time from any existing address where they already have a scheduled appointment that day and has available time in there schedule. Thus the dispatching system when a new service call is entered is going to give "recommended" technicians (up to 4) to be assigned the new service call based on the above mentioned criteria. (Efficient routing to save company gas cost)

 

1.) We have a "New service" street address assigned to the $to variable: $to = "4813 River Basin Dr S, Jacksonville FL 32207";
 

 

2.) We will have "records" array which containes a series of records, each record consists of a ticket# a technician id# and a street address:

$records = array(
array("DV1012","30453423","9890 Hutchinson Park Dr Jacksonville, FL 32225"),
array("DB3434","30404041","821 Orange Ave Crescent City, FL 32112"),
array("DB3434","30605060","1972 Wells Road, Orange Park FL 32073"),
array("DB4578","30605060","2 Independent Drive, Jacksonville FL 32202"),
array("DB7841","30605060","5000 Norwood Avenue, Jacksonville FL 32208"),
array("DB3235","30605060","9501 Arlington Expressway, Jacksonville FL 32225"),
array("DB7894","30605060","Massey Avenue, Jacksonville, FL 32227"),
array("DB2020","30121212","11200 Central Pkwy Jacksonville, FL 32224")
                );

 

3.) We are going to prepare the records array for submission to Google's Distance Matrix API by URL encoding each array value into a single variable and then submit it:

 

foreach ($records as $key => $value) {$from = $from.urlencode($value[2])."|";}

$to = urlencode($to);
$data = file_get_contents("//maps.googleapis.com/maps/api/distancematrix/json?origins=$from&destinations=$to&language=en-EN&units=imperial&mode=driving&sensor=false");
$res=json_decode($data) or die("Error: Cannot read object");

 

You may look at the ACTUAL live Google response from this here: http://tiny.cc/i6eerx  (We have applied <pre> and var_dump($res) to the output)

 

We are looking to get the following information back: The distance and travel time between the "New Service" address ($to) and each of the address' in the $records array ($from), now once that information is returned from Google (JSON response) we need to parse the response and narrow it down to 4 or less (Based on the 4 lowest drive times) to form a new array which ends like this:

 

$results = array(
array("DV1012","30453423","2.3 Miles","8 mins"),
array("DB3434","30404041","2.8 Miles","9 mins"),
array("DB3434","30605060","4.6 Miles","13.8 mins"),
array("DB4578","30605060","5.7 Miles","15.2 min")
                );

OUR PROBLEM: Everything up until the the Google API response is fine, but iterating over the multidimensional arrays within multidimensional arrays of the JSON response is just not coming together in my head (or 2 dozen code attempts). I am able to ECHO an individual value like ( echo $res->rows[0]->elements[0]->distance->text; ) but this has no value for the end result i need to get to. My last thoughts and efforts was that that I was going to have to embed foreach statements within foreach statements to drill down through the various arrays but that hasn't worked very well and it seems like it shouldn't be how it has to be done. I would appreciate any help in showing me how the iteration code should be written and any explanation about the code so i can wrap my head around it.

Link to comment
Share on other sites

echo $res->rows[0]->elements[0]->distance->text;
Each of those [0]s is something you could foreach over. However only one, for rows, needs it as the other is "always" just [0].

 

The data is organized such that each address in origin_addresses has a corresponding key in the rows array; the Hutchinson Park Drive address (0) corresponds to rows[0], and so on. This is the same order that you passed the addresses.

Instead of foreach-ing over the rows you can do it over your $records array. Worry about sorting after.

foreach ($records as $key => $value) {
    // find $res->rows[$key]
Then you piece together $results.

$results[] = array($value[0], $value[1], $res->rows[$key]->elements[0]->distance->text, $res->rows[$key]->elements[0]->duration->text);
Now you can deal with sorting. array_multisort can do it but you have to give it an array of values to sort by. Put the distance's "value" into a separate array at the same time - not "text" as that's not a sortable value (well, it is, but not as easily as the raw value).

$results = $distances = array();
foreach ($records as $key => $value) {
    $results[] = array($value[0], $value[1], $res->rows[$key]->elements[0]->distance->text, $res->rows[$key]->elements[0]->duration->text);
    $distances[] = $res->rows[$key]->elements[0]->distance->value;
}
Pass both those arrays to array_multisort(): first $distances with sorting options, then $results without options. Afterwards $distances will be sorted in order and $results will be arranged to match. Edited by requinix
Link to comment
Share on other sites

By default, when you sort an array of arrays, the arrays are sorted on the first element. So you could put the distance at the start of each array and then just sort().

$results =  [
                [5, 'abc', 'defg'],
                [8, 'def', 'efg'],
                [12, 'ghj', 'fghij'],
                [10, 'klm', 'ghijk'],
                [8, 'nop', 'lmn'],
            ];
sort($results);
echo '<pre>SORTED ',print_r($results, true),'</pre>';

gives

SORTED Array
(
    [0] => Array
        (
            [0] => 5
            [1] => abc
            [2] => defg
        )

    [1] => Array
        (
            [0] => 8
            [1] => def
            [2] => efg
        )

    [2] => Array
        (
            [0] => 8
            [1] => nop
            [2] => lmn
        )

    [3] => Array
        (
            [0] => 10
            [1] => klm
            [2] => ghijk
        )

    [4] => Array
        (
            [0] => 12
            [1] => ghj
            [2] => fghij
        )

)
Link to comment
Share on other sites

Requinix:   Thank you, Although some of your answer lost me it was enough for me to try a alternate approach which eventually led to a working answer.

Barand: Thank you, I have not implimented your suggestion yet, but I will as it is straight forward on sorting how i need.

 

To both of you: Thnak you for the answers and help, below is the end code (sorting excluded for the moment)

$to = "4813 River Basin Dr S, Jacksonville FL 32207";

$records = array(
array("DV1012","30453423","9890 Hutchinson Park Dr Jacksonville, FL 32225"),
array("DB3434","30404041","821 Orange Ave Crescent City, FL 32112"),
array("DB3434","30605060","1972 Wells Road, Orange Park FL 32073"),
array("DB4578","30605060","2 Independent Drive, Jacksonville FL 32202"),
array("DB7841","30605060","5000 Norwood Avenue, Jacksonville FL 32208"),
array("DB3235","30605060","9501 Arlington Expressway, Jacksonville FL 32225"),
array("DB7894","30605060","Massey Avenue, Jacksonville, FL 32227"),
array("DB2020","30121212","11200 Central Pkwy Jacksonville, FL 32224")
                );
                
foreach ($records as $key => $value) {$from = $from.urlencode($value[2])."|";}
$result = array();                
$to = urlencode($to);
$data = file_get_contents("http://maps.googleapis.com/maps/api/distancematrix/json?origins=$from&destinations=$to&language=en-EN&units=imperial&mode=driving&sensor=false");
$res=json_decode($data) or die("Error: Cannot read object");

$time = 0; $distance = 0;

$limit = count ($res->rows);
for ($i = 0; $i < $limit; $i++) {
foreach($res->rows[$i]->elements as $road) {
    $time += $road->duration->value;
    $distance += $road->distance->value;
    $distance = round(($distance * 0.00062),2);
    $time = ceil($time / 60);
    $ticket = $records[$i][0];
    $from = $res->origin_addresses[$i];
    $to = $res->destination_addresses[0];

    $result[$ticket] = "$time"; //The end result array is a ticket# with a matching  travel "time" between common point A and the other address point B...C...D...etc.etc.

echo "Ticket: ".$ticket."<br>";
echo "From: ".$from;
echo "<br/>";
echo "To: ".$to;
echo "<br/>";
echo "Time: ".$time." minutes";
echo "<br/>";
echo "Distance: ".$distance." miles";
echo "<hr>";


                                          }
                            }
Edited by dmsinc
Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.