2011-06-16 103 views
0

下面的鍵值從php_decoded JSON結構的exerpt,我有工作:PHP問題更改遞歸JSON陣列

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) "<>" 
      } 

我一直在試圖寫這個函數,遞歸地追溯了JSON對象,並替換目標值爲$ postvalue,但每當我嘗試遞歸執行此操作時,值都不會更改。這是我到目前爲止的代碼:

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; 
       } 
     } 
} 

有趣的是,如果我直接索引到結構如下所示:

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

值是可以改變的。似乎是唯一的問題是遞歸。這聽起來像是一個很容易解決的問題,但我只是編程了不到一年的時間,所以我可能只是缺少一些明顯的東西。 >。>

哦,postvalue和postkey值來自HTML表單提交。

--edit-- print語句就在那裏進行調試。它可以被忽略。

編輯2: 下面是函數是如何調用:

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

再次,打印語句是調試目的。 附加信息:HTML輸入字段的名稱是根據其在JSON樹中的順序動態分配的數字。因此,遞增變量idCounter對應於繼續到下一個輸入字段。
Edit3:在註釋中添加了代碼。

+0

我通過你的描述看到你想用新值替換一個鍵,但是從給出的代碼中,它確實有更多的邏輯。你可以展示一個實例嗎? – Lumbendil 2011-06-16 20:50:01

+0

是的,對不起。我試圖儘可能保持簡單。我在第二次編輯中添加了呼叫。 – Richard 2011-06-16 21:06:20

+0

你能解釋一下這個功能究竟是做什麼的嗎?我能讀到的是以下內容:如果級別低於閾值,它只是遞歸。達到級別時:對於每個元素,它檢查是否存在'$ idCounter == $ postvalue'。在這種情況下,它用'$ value'替換該鍵。在另一種情況下,它只會增加'$ idCounter'。 – Lumbendil 2011-06-16 21:34:12

回答

1

你可以(也應該)總是使用PHP的內部函數,以防萬一。

如果你不需要櫃檯,你可以看看array_replace_recursive。在這種情況下,你的代碼應該是這樣的:

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

編輯

目前的意見後:

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; 
      } 
    } 
} 

的問題是,在遞歸,你在哪裏使用$value,這是數組元素的拷貝。然後,這是編輯,但更改不傳播到$json

+0

AH美麗!非常感謝 :) – Richard 2011-06-17 02:08:19

0

還有另一種方法可以做到這一點。主要想法是將JSON視爲一個字符串,然後使用str_replacepreg_replace(str_replace for regexp)。有一個示例:

# 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); 

注意:最好使用完全匹配來替換字符串。有一種方法可以做到。

# 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);