【问题标题】:PHP Problem changing key values recursively in JSON arrayPHP问题在JSON数组中递归更改键值
【发布时间】:2011-09-16 16:49:04
【问题描述】:

这是我正在使用的 php_decoded 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 表单提交。

--编辑-- 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:在 cmets 中添加到代码中。

【问题讨论】:

  • 我从你的描述中看到你想用一个新的值替换一个键,但是从给出的代码来看,它做了更多的逻辑。你能显示一个例子吗?
  • 是的,对不起。我试图使帖子尽可能简单。我在第二次编辑中添加了调用。
  • 你能解释一下这个函数是做什么的吗?我能读到以下内容:如果水平低于阈值,它只会递归。达到级别时:对于每个元素,它检查是否$idCounter == $postvalue。在这种情况下,它会将密钥替换为$value。在另一种情况下,它只是增加了$idCounter
  • 我只是在 cmets 中添加了详细说明。最低级别的键/值对在网页中由输入字段表示。这些输入字段的名称只是由先前文件中的计数器分配的。当 idCounter 等于 Postkey 时,该函数已到达所需键。然后应该只是用 Postvalue 替换该键的值。

标签: php json recursion


【解决方案1】:

您可以(并且应该)始终使用 PHP 的内部函数,以防万一。

如果您不需要计数器,可以查看array_replace_recursive。在这种情况下,您的代码将如下所示:

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

编辑

在当前 cmets 之后:

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

【讨论】:

  • 漂亮啊!非常感谢:)
【解决方案2】:

还有另一种方法可以做到这一点。主要思想是将 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);

【讨论】:

    猜你喜欢
    • 2015-09-05
    • 1970-01-01
    • 2015-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-06
    • 2019-09-06
    • 2015-02-04
    相关资源
    最近更新 更多