1

My goal is to have a function that can remove a specified json child, which could also be nested inside deeper.

My function looks like this:

private function removeJsonChild(String $jsonKey, String $jsonString)
{
    $json = json_decode($jsonString, true);
    $arr_index = array();

    foreach ($json as $key => $value) {
        if (is_array($value)) {
            $json[$key] = $this->removeJsonChild($jsonKey, json_encode($value));
        }

        if ($key == $jsonKey) {
            $arr_index[] = $key;
        }
    }

    foreach ($arr_index as $i) {
        unset($json[$i]);
    }

    return json_encode($json);
}

The function would work if i wouldn't check if a $value is an array and then call the function again recursively. But there is the problem i think. In the statement where i assign the return value of the function to $json[$key]. What am i doing wrong?

EDIT: definitely forgot a json_decode. New code looks like this:

private function removeJsonChild(String $jsonKey, String $jsonString)
{
    $json = json_decode($jsonString, true);
    $arr_index = array();

    foreach ($json as $key => $value) {
        if (is_array($value)) {
            $json[$key] = json_decode($this->removeJsonChild($jsonKey, json_encode($value)));
        }

        if ($key == $jsonKey) {
            $arr_index[] = $key;
        }
    }

    foreach ($arr_index as $i) {
        unset($json[$i]);
    }

    return json_encode($json);
}

EDIT2:

The function works now, however it slightly changes the json schema.

An JSON like this:

[
  {
    "id": 1,
    "name": "oyzadsaigny647"
  }
]

now becomes this:

{
  "1": {
    "id": 1,
    "name": "oyzadsaigny647"
  }
}
Bioaim
  • 928
  • 1
  • 13
  • 26
  • 4
    First of all, separate the responsibilities here. Write one recursive function that can remove keys from arrays. Then write a second function which cares about the en-/decoding to/from JSON. – deceze May 23 '19 at 07:31
  • does it work with the json_decode? – gbalduzzi May 23 '19 at 07:37
  • see my last edit – Bioaim May 23 '19 at 07:42
  • 1
    This looks like a perfect example project to learn TDD - try to write test cases, starting from the simplest one, to cover that requirement. If something along that way is not working out, share your attempts – Nico Haase May 23 '19 at 07:46
  • See https://stackoverflow.com/q/3869129/476 – deceze May 23 '19 at 07:48

1 Answers1

2
private function removeJsonChild(String $jsonKey, String $jsonString) {

   $data = json_decode($jsonString, true);

   $data = $this->removeKeyFromArray($key, $data);

   return json_encode($data);

}

private function removeKeyFromArray(String $deleteKey, array $data) {

  unset($data[$deleteKey]); // No need to check if it exists, it just does nothing in that case

  foreach($data as $key => value) {
    if(is_array($value)) {
        $data[$key] = $this->removeKeyFromArray($deleteKey, $value);
    }
  }
  return $data;
}

NOTE: this will work in case of dictionaries, i.e. array with actual keys. If you have a plain array such as [1, 10, 23, 15] the unset behaviour is wrong, as pointed out by @deceze♦

gbalduzzi
  • 9,356
  • 28
  • 58
  • thank you for your answer. works perfetly fine for such json objects: `{ "id": 1, "name": "oyziasasgny647", "status": "active", "lastUpdate": "2019-03-08T00:00:00+00:00" }` but does not for this: `[ { "id": 1, "name": "oyziasasgny647", "status": "active", "lastUpdate": "2019-03-08T00:00:00+00:00" } ]` it isn't deleting the `lastUpdate` key in that case. – Bioaim May 23 '19 at 08:05
  • the problem is, i don't exactly know the schema of the json before executing the function. – Bioaim May 23 '19 at 08:08
  • There was an overlapping of `$key` variable, my fault. See my edited answer. – gbalduzzi May 23 '19 at 08:32
  • Btw the problem in my `NOTE` comment would only arise if you use a number as the key to remove – gbalduzzi May 23 '19 at 08:33
  • ok thanks. when i try to remove `latestVersion` it doesn't seem to unset it for this schema: `[ { "id": 1, "name": "oyzignasasady647", "status": "active", "latestVersion": "8.9.8", "description": "this is a desc", "descriptionShort": "shortDesc", "contacts": [ "\/api\/contacts\/2" ] }, { "id": 2, "name": "ueflasaslqc883", "status": "inactive", "latestVersion": "0.8.0", "description": "desc", "descriptionShort": "shortdesc", "contacts": [ "\/api\/contacts\/18" ] } ]` – Bioaim May 23 '19 at 08:41
  • it just ignores it and it is still part of the new array which is returned. – Bioaim May 23 '19 at 08:41
  • I still forgot one `$key` instead of `$deleteKey` damn – gbalduzzi May 23 '19 at 09:02