PHP The problem of changing key values ​​recursively in a JSON array

Here is an excerpt from the JSON php_decoded structure I'm working with:

array(3) { ["$type"]=> string(51) "NanoWebInterpreter.WebInputData, NanoWebInterpreter" ["NBBList"]=> array(2) { ["$type"]=> string(81) "System.Collections.Generic.List`1[[monoTNP.Common.NBB, monoTNP.Common]], mscorlib" ["$values"]=> array(1) { [0]=> array(6) { ["$type"]=> string(34) "monoTNP.Common.NBB, monoTNP.Common" ["ID"]=> string(16) "id-0065-00000003" ["MPList"]=> array(2) { ["$type"]=> string(80) "System.Collections.Generic.List`1[[monoTNP.Common.MP, monoTNP.Common]], mscorlib" ["$values"]=> array(3) { [0]=> array(9) { ["$type"]=> string(43) "monoTNP.Common.EllipticalMP, monoTNP.Common" ["Eccentricity"]=> float(1) ["ID"]=> string(16) "id-0065-00000006" ["ParticleIndex"]=> int(-1) ["DispersionInteractionStrength"]=> float(0) ["DispersionInteractionRange"]=> float(2.5) ["CharacteristicSize"]=> float(0) ["CenterOfMass"]=> string(7) "<0,0,0>" ["OrientationVector"]=> string(2) "<>" } 

I am trying to write this function that recursively traces a JSON object and replaces the target value with the value of $ postvalue, but whenever I try to do this recursively, the value does not change. Here is my code:

 function replaceVal(&$json, $postkey, $postvalue, &$idCounter, $level) { $depth = 3; #Base Case #At the right depth level, check to see if the idCounter is equal to the #postkey value (the HTML input field name). If it is, take the #corresponding key and assign the postvalue to it (the input from form). #Then return. Otherwise, incrememnt the idCounter and return. if ($level >= $depth){ foreach($json as $key => $value){ if($idCounter == $postkey){ print "$key => $value\n"; $json[$key] = $postvalue; #Not working properly return; } $idCounter++; } } #Descend down into the level of the tree specified by $depth. #This level should correspond do the level at which the HTML input #fields lie #$idCounter will only be greater than $postkey if the value has #been changed by the previous if statement. In that case, the job is done #and the function will terminate. if ($level < $depth){ foreach($json as $key => $value){ if ($idCounter < $postkey) replaceVal($value, $postkey, $postvalue, $idCounter, $level+1); else return; } } } 

The interesting part is that if I directly index into the structure as follows:

 $key = &$json['NBBList']['$values'][0]['MPList']['$values'][0]['Eccentricity'] $key = "asdf"; 

The value can be changed. The only thing that seems to be the problem is recursion. This sounds like a very simple problem to fix, but I only programmed a little less than a year, so probably I just don't see anything obvious. >. >

Oh, and the values ​​of postvalue and postkey are derived from the presentation of the HTML form.

- edit-- The print statement is there for debugging. It can be ignored.

Edit 2: This is how the function is called:

 foreach ($_POST as $postkey => $postvalue) { if ($postvalue != ""){ print "$postkey => $postvalue\n"; $idCounter = 1; replaceVal($json['NBBList']['$values'][0], $postkey, $postvalue, $idCounter, 0); } } 

Again, the print expression is for debugging purposes. Additional Information: The names of the HTML input fields are dynamically assigned numbers according to their order in the JSON tree. Thus, the increment of the idCounter variable corresponds to the transition to the next input field.
Edit3: added to the code comment.

0
source share
2 answers

You can (and should) always use the PHP internal function, in case it exists.

If you don't need a counter, you can look at array_replace_recursive . In this case, your code will look like this:

 function replaceVal(&$array, $key, $value) { $array = array_replace_recursive( $array, array( $key => $value ) ); } 

EDIT

After current comments:

 function replaceVal(&$json, $postkey, $postvalue, &$idCounter, $level) { $depth = 3; if ($level >= $depth){ foreach($json as $key => $value) { if($idCounter == $postkey) { $json[$key] = $postvalue; #Not working properly return; } $idCounter++; } } if ($level < $depth){ foreach($json as $key => $value){ if ($idCounter < $postkey) replaceVal($json[$key], $postkey, $postvalue, $idCounter, $level+1); else return; } } } 

The problem was that in recursion, you are using $value , which is a copy of the array element. This was then edited, but the changes did not apply to $json .

+1
source

There is another way to do this. The main idea is to treat JSON as a string, and then use str_replace or preg_replace (str_replace for regexp). There is an example:

 # Creating a mapping array ("old_key_name" => "new_key_name"). # There I'm reading a mapping from the json file $mapping_json_file. # But you can set your mapping array directly instead, like $mapping_array = array("old_key_name" => "new_key_name",...). $mapping_array = json_decode(file_get_contents($mapping_json_file),true); # Replace string $new_json = str_replace(array_keys($mapping_array ), array_values($mapping_array), $old_json); 

NOTE: it would be better to use full match to replace the string. There are several ways to do this.

 # For each key name, replace each $old_key_name by "/\b".$old_key_name."\b/u". # It needed for recognizing breakers. $tmp_arr = array_map(function($k){ return '/\b'.$k.'\b/u'; }, array_keys($mapping_array)); # Now we use "/\b".$old_key_name."\b/u" instead $old_key_name. $new_json = preg_replace($tmp_arr, array_values($mapping_array), $old_json); 
0
source

Source: https://habr.com/ru/post/887489/


All Articles