2
[
    'one/two' => 3,
    'one/four/0' => 5,
    'one/four/1' => 6,
    'one/four/2' => 7,
    'eight/nine/ten' => 11
]

I am attempting to build the above array based on $json_str:

$json_str = '{
    "one":
    {
        "two": 3,
        "four": [ 5,6,7]
    },
    "eight":
    {
        "nine":
        {
            "ten":11
        }
    }
}';

I built a recursive function that loops thru this $json_str but so far I can only get strings to output.

How would I build an array instead echoing a string?

Also, how would I get only index values that belong in the associative index to be there.

Currently I can only get all keys to print:

one/two => 3

one/two/four/0 => 5

one/two/four/0/1 => 6

one/two/four/0/1/2 => 7

one/eight/nine/ten => 11

Below is what I have so far:

<?php

function printAll($a, $prefix = '') {

  if (!is_array($a) && !is_object($a)) {

    $prefix = rtrim($prefix, '/');

    echo $prefix . ' => ' . $a, "\n";

    return;
  }

  foreach($a as $k => $v) {

    $prefix .= $k . "/";

    printAll($v, $prefix);
  }
}


$json_str = '{
                "one":
                {
                    "two": 3,
                    "four": [ 5,6,7]
                },
                "eight":
                {
                    "nine":
                    {
                        "ten":11
                    }
                }
            }';


$object = json_decode($json_str);
printAll($object);

2 Answers 2

3

You could use an array to hold the keys of object, instead of using a string, and array_pop() to remove the last one at the end of the loop. So you have a stack of the keys which can be used to get the breadcrumb of the JSON data.

function printAll(&$out = [], $a, $prefix = []) {
    foreach ($a as $key => $value) {
        $prefix[] = $key;  // add the key to "prefix"
        if (is_array($value) || is_object($value)) {
            printAll($out, $value, $prefix);
        }else{
            $out[implode('/', $prefix)] = $value;
        }
        // remove current key because we are no more inside it.
        array_pop($prefix);
    }
}

$json_str = '{"one": {"two": 3, "four": [ 5,6,7] }, "eight": {"nine": {"ten":11 } } }';

$object = json_decode($json_str);
$data = [];
printAll($data, $object);
print_r($data);

Outputs:

Array
(
    [one/two] => 3
    [one/four/0] => 5
    [one/four/1] => 6
    [one/four/2] => 7
    [eight/nine/ten] => 11
)
Sign up to request clarification or add additional context in comments.

5 Comments

Thank you. This works. What happens to $prefix value 'one/four' after value 7 is added to array? 'one/four/2' gets the '2' array_popped off the end after value 7 is added to array but when index 'eight' is processed $prefix is blank and not what I expected which is "one/four"
Thank you for your feedback. I'm sure to really understand. Could you give me a JSON that fail, please?
Same JSON string as in the program: $json_str = '{"one": {"two": 3, "four": [ 5,6,7] }, "eight": {"nine": {"ten":11 } } }'; I was wondering how the $prefix is reset to blank string "" when associative index "eight" is processed. I thought $prefix would still be "one/four" from previous iterations
The $prefix is equal to one/four during 7, but one, after ] (out of the array), and empty after } (out of the object). Because the $prefix is sent to the recursive function, it appends the new prefix when enter in array or object, and pop when out.
To see it in action, you could add an echo when push, pop, and enter in the function.
1

You modify $prefix inside the foreach loop. Therefore the changes will be there in each subsequent iteration of the loop. You should be fine if you cache your output in a temporary variable:

foreach($a as $k => $v) {
    $tmp = $prefix;
    $tmp .= $k . "/";
    printAll($v, $tmp);
}

Now if you want to build an array instead of echoing you can simply pass the array by reference, and build it:

function printAll($a, &$output, $prefix = '') {
  if (!is_array($a) && !is_object($a)) {
    $prefix = rtrim($prefix, '/');
    $output[]= $prefix . ' => ' . $a. "\n";
    return;
  }
  foreach($a as $k => $v) {
    $tmp = $prefix;
    $tmp .= $k . "/";
    printAll($v, $output, $tmp);
  }
}

I put a demo here: https://3v4l.org/LSvZN

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.