-1

I need a function that converts PHP nested JSON Object/Array to an Associative Array.

$final_array=[];
function toArray($initial,$json_object){
    foreach($json_object as $key => $value){
        if($value is string or integer or ...){  //Requires to be changed.
             $final_array[$initial.'/'.$key]=$value;
        }
        else{
             toArray($initial.'/'.$key,$value);
        }
    }
}

$json='{
    "name":{
         "first_name":"James",
         "last_name":"Bond"
     },
     "aliases":["007","Bond"],
     "profiles":[{"0":"unknown"},"007",{"2":"secret agent"}]
}';

toArray('/Bond',json_decode($json));

foreach($final_array as $key=>$value){
     echo $key.' - '.$value;
}

And Desired output is:

/Bond/name/first_name - James
/Bond/name/last_name - Bond
/Bond/aliases/0 - 007
/Bond/aliases/1 - Bond
/Bond/profiles/0/0 - Unknown
/Bond/profiles/1 - 007
/Bond/profiles/2 - secret agent

What changes will I have to make in the code to get the desired functionality?

7
  • Why not just json_decode($json, true)? Commented Apr 28, 2018 at 20:59
  • I am so sorry, I missed that out in code. I have fixed it. Commented Apr 28, 2018 at 21:02
  • first question: Why do you wanna put that as array key? I would just calculate 'paths' for each item (recoursively) Commented Apr 28, 2018 at 21:02
  • @AniruddhaSarkar you've missed my point, please look back at my comment. The second parameter turns the object in to an associative array and then you can just loop through an make the format as you want. Commented Apr 28, 2018 at 21:02
  • @Jeff that would be a solution to my problem. I guess you can suggest me the code. Commented Apr 28, 2018 at 21:03

4 Answers 4

2

this seem to work:

<?php
function wtf(string $root_name,Iterable $data){
    foreach($data as $name=>$val){
        if(is_iterable($val)){
            wtf($root_name."/".$name,$val);
        }else{
            echo $root_name."/$name - $val"."\n";
        }
    }
}


$json='{
    "name":{
         "first_name":"James",
         "last_name":"Bond"
     },
     "aliases":["007","Bond"],
     "profiles":[{"0":"unknown"},"007",{"2":"secret agent"}]
}';
$data=json_decode($json,true);
wtf('/bond',$data);

output:

/bond/name/first_name - James
/bond/name/last_name - Bond
/bond/aliases/0 - 007
/bond/aliases/1 - Bond
/bond/profiles/0/0 - unknown
/bond/profiles/1 - 007
/bond/profiles/2/2 - secret agent
Sign up to request clarification or add additional context in comments.

3 Comments

yep, yours is much shorter than mine. but echoes directly in the function, what I tried to avoid.
@Jeff then try function wtf(string $root_name,Iterable $data,string $str=NULL):string{ if(!is_string($str)){ $str=""; } foreach($data as $name=>$val){ if(is_iterable($val)){ $str=wtf($root_name."/".$name,$val,$str); }else{ $str.=$root_name."/$name - $val"."\n"; } } return $str; }
I'm not the OP, I just gave another answer, and wanted to give you credits for a good (and completely different than my) answer! It's on the OP now to chose which suits best for his needs.
1

Convert it to a generic object data type thingie and then build it out.

This may help -

<?php

$json='{
    "name":{
         "first_name":"James",
         "last_name":"Bond"
     },
     "aliases":["007","Bond"],
     "profiles":[{"0":"unknown"},"007",{"2":"secret agent"}]
}';


function printobj($o){
  foreach($o as $p=>$v){
    if(is_object($v)){
     printobj($v);
    }elseif(is_array($v)){
     printobj(json_decode(json_encode($v)));
    }else{
     print $p." = ".$v."\n";
    }
  }
return;
}

$object=json_decode($json);
printobj($object);

    ?>

3 Comments

this doesn't give the full path, does it?
I got what to write in the blank though
I provided a hint so (s)he can solve the issue on their own. I was under the impression this was a help forum, not a "write my code for free for me" service...
1

Here's a solution:

<?php

function getPaths($a, $output = Array(), $parents = array()) {
    // resetting path
    $path = $parents;

    // walk through the items
    foreach($a as $key => $value) {     
        if(is_array($value)) {
            $path[] = $key;
            // get the sub-items
            $output = getPaths($value, $output, $path);
        } else {
            $path[] = $key;
            // build return array
            $x = ["path" => $path, "value" => $value];
            // add that to output
            $output[] = $x;

        }
        $path = $parents; // again a reset..
    }
    return $output;
}

// usage:

$json='{
    "name":{
         "first_name":"James",
         "last_name":"Bond"
     },
     "aliases":["007","Bond"],
     "profiles":[{"0":"unknown"},"007",{"2":"secret agent"}]
}';
$array = json_decode($json, true);

foreach(getPaths($array) as $item) {
    echo "Bond/".implode("/",$item['path']) . " - {$item['value']} <br>";
}

Output:

Bond/name/first_name - James
Bond/name/last_name - Bond
Bond/aliases/0 - 007
Bond/aliases/1 - Bond
Bond/profiles/0/0 - unknown
Bond/profiles/1 - 007
Bond/profiles/2/2 - secret agent

Comments

0

My pathify() function declares a storage variable $output inside the function which can receive pushed data from anywhere in the recursive process because it is modifiable by reference (denoted by the & symbol before variable).

As long as $v is an array, the function will call itself with the updated/extended $path value. When $v ceases to be an array, the path value is appended with a - then $v.

By calling implode("\n", pathify(...)), my approach ensure that there are no dangling/extra newline characters -- only between visible strings.

Code: (Demo)

function pathify($array, $path, &$output = []){  // declare $output as an empty array by default and modify by reference
    foreach($array as $k => $v){
        if (is_array($v)) {                      // if can recurse
            pathify($v, "$path/$k", $output);    // append key to path, access $v array
        }else{
            $output[] = "$path/$k - $v";         // push completed string to output array
        }
    }
    return $output;                              // return array of path strings
}

$json='{
    "name":{
         "first_name":"James",
         "last_name":"Bond"
     },
     "aliases":["007","Bond"],
     "profiles":[{"0":"unknown"},"007",{"2":"secret agent"}]
}';

$data = json_decode($json, true);              // decode json to an array
echo implode("\n", pathify($data, "/Bond1"));  // separate the returned string with a newline
echo "\n-------\n";
echo implode("\n", pathify([], "/Bond2"));     // separate the returned string with a newline
echo "\n-------\n";
echo implode("\n", pathify([], "/Bond3"));     // separate the returned string with a newline
echo "\n-------\n";
echo implode("\n", pathify($data, "/Bond4"));  // separate the returned string with a newline
echo "\n-------\n";
echo implode("\n", pathify($data, "/Bond5"));  // separate the returned string with a newline

Output:

/Bond1/name/first_name - James
/Bond1/name/last_name - Bond
/Bond1/aliases/0 - 007
/Bond1/aliases/1 - Bond
/Bond1/profiles/0/0 - unknown
/Bond1/profiles/1 - 007
/Bond1/profiles/2/2 - secret agent
-------

-------

-------
/Bond4/name/first_name - James
/Bond4/name/last_name - Bond
/Bond4/aliases/0 - 007
/Bond4/aliases/1 - Bond
/Bond4/profiles/0/0 - unknown
/Bond4/profiles/1 - 007
/Bond4/profiles/2/2 - secret agent
-------
/Bond5/name/first_name - James
/Bond5/name/last_name - Bond
/Bond5/aliases/0 - 007
/Bond5/aliases/1 - Bond
/Bond5/profiles/0/0 - unknown
/Bond5/profiles/1 - 007
/Bond5/profiles/2/2 - secret agent

Big thanks to @hanshenrik for alerting me to the crippling impact on function re-usability with my first answer which used a static $output declaration. If interested in researching this drawback please, read the following page and the comments. static keyword inside function?

2 Comments

don't try to call that function twice in the same execution tho, it never clears $output
@hanshenrik That was an excellent, excellent bullet to hit me with -- thank you. (...grrr, now I need to search for a few other answers of mine with the same flaw.) I appreciate the lesson.

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.