0

Here is an exerpt from the php_decoded JSON structure that I am 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 have been trying to write this function that recursively traces the JSON object and replaces the target value with $postvalue, but whenever I try to do this recursively, the value isn't changed. Here is my code so far:

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 like so:

$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 the recursion. This sounds like a really easy problem to fix, but I've only been programming for a little less than a year so I am probably just missing something obvious. >.>

Oh and the postvalue and postkey values come from an HTML form submission.

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

Edit 2: Here 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 statement is for debugging purposes. Additional info: The names of the HTML input fields are dynamically assigned numbers based on their order in the JSON tree. So, incrementing the variable idCounter corresponds to proceeding to the next input field.
Edit3: added in comments to code.

4
  • I see by your description that you want to replace a key with a new value, but from the code given, it does quite a bit more of logic. Could you show an exaple call? Commented Jun 16, 2011 at 20:50
  • Yes, sorry. I was trying to keep the post as straightforward as possible. I added the call in the second edit. Commented Jun 16, 2011 at 21:06
  • could you explain exactly what the function is meant to do? What i can read is the following: If the level is below a treshold, it just recurses. When the level is reached: For each element, it checks if $idCounter == $postvalue. In that case, it replaces the key with $value. In another case, it just increases $idCounter. Commented Jun 16, 2011 at 21:34
  • I just added in comments to elaborate. The lowest level key/value pairs are represented in a web page by input fields. The names of those input fields are just assigned by a counter from a previous file. When the idCounter equals the Postkey, the function has reached the desired key. It should then just be a matter of replacing the value of that key with the Postvalue. Commented Jun 16, 2011 at 21:53

2 Answers 2

1

You can (and should) allways use PHP's internal function, in case there is any.

If you don't need the counter, you could look at array_replace_recursive. In that case, your code would 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 the recursion, you where using $value, wich is a copy of the array element. Then, that was edited, but the changes didn't propagate to $json.

Sign up to request clarification or add additional context in comments.

Comments

0

There is another way to do it. The main idea is to consider 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 for string replace. There is a siple way one can do it.

# For each key name, replace each $old_key_name by "/\b".$old_key_name."\b/u". 
# It's 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);

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.